2017-02-18 4 views
0

Unten ist ein vielleicht dummes Beispiel, aber ich denke, das Lösen wird ein anderes Problem, das ich habe, detailliert in this question.Optimierung basierend auf Funktion Ergebnis Typ

Ich mag eine Funktion mit dieser Signatur schreiben:

myread :: (Read a) => String -> a 

so dass myread = read, außer wenn a ~ Int, wobei in diesem Fall myread _ = 0.

Offensichtlich ist diese Funktion albern selbst, aber der Punkt ist, ich möchte basierend auf Rückgabetyp optimieren.

Regeln neu schreiben, oder alles ist in Ordnung hier. Für mein tatsächliches Problem, wenn die Lösung eine Rewrite-Regel ist, spielt es keine Rolle, ob es Fälle gibt, in denen es nicht zündet, aber ich möchte die Antwort, um wenigstens ein Beispiel zu geben, wo es ist.

+0

Es scheint, als ob Sie bereits das richtige Werkzeug zur Hand haben - die Klassenbeschränkung für 'a'. Sie kontrollieren natürlich nicht die 'Read Int' -Instanz, aber es scheint, dass Sie in Ihrem tatsächlichen Anwendungsfall die Definition und die Instanzen der Klasse steuern. Oder vielleicht habe ich missverstanden, was Sie mit "optimieren" meinen? (beiseite: Ich denke, die Lösung in der anderen Antwort funktioniert nicht, weil 'x :: H a => T a 'nicht" x vom Typ T a im Kontext H a "sondern" x vom Typ' H "bedeutet a => T a ", dh die Regel würde angewendet auf' (Lesen a => F a) -> X 'nicht' Lesen a => F a -> X ') – user2407038

+0

Ich kontrolliere nicht das 'Read' Klasse, und ich kann nicht meine 'Read' -Instanz für' Int' erstellen, wenn eine bereits existiert. Vielleicht verstehe ich dich falsch. – Clinton

Antwort

0

Wie wäre es mit einer neuen Klasse mit unentscheidbaren Instanzen?

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE UndecidableInstances #-} 

class MyRead a where 
    myread :: String -> a 

instance {-# OVERLAPPABLE #-} Read a => MyRead a where 
    myread = read 

instance MyRead Int where 
    myread = const 0 

main = do 
    print $ (myread "True" :: Bool) -- True 
    print $ (myread "\"string\"" :: String) -- "string" 
    print $ (myread "12" :: Int) -- 0 
+0

In diesem Fall hat 'MyRead' die Signatur' myread :: MyRead a => String -> a'. Wie in der Frage erwähnt, muss die Signatur "myread :: Read a => String -> a" sein (sonst wird das Problem in der verwandten Frage nicht gelöst). – Clinton

1

Sie können dies mit Rewrite-Regeln direkt zu tun, in (vielleicht) die offensichtliche Art und Weise, wenn Sie sich erinnern, dass die linke Seite einer Regel in einem ist Ausdruck Zusammenhang nicht in einem Muster Kontext . Insbesondere sind Anwendungen auf der linken Seite absolut gültig.

{-# LANGUAGE TypeApplications #-} 

module A where 

{-# INLINE [1] myread #-} 
{-# RULES "myread" forall s . myread @Int s = 0 #-} 

myread :: Read a => String -> a 
myread = read 

Auch ohne Typ-Anwendungen ist die folgende auch vollkommen gültig (aber nicht im allgemeinen sein, zB wenn der Ausgabetyp f a war und man wollte ‚Optimieren‘ nur f, Sie nicht .. = (result :: [ _ ]) haben könnte):

{-# RULES "myread" forall s . myread s = (0 :: Int) #-} 

Und als Beispiel

module B where 

import A 

fun :: String -> String -> (Int, Bool) 
fun x y = (myread x, myread y) 

der Beweis verwenden, dass die Regel feuert immer auf Kern zu suchen ist, natürlich (irrelevant Bits weggelassen):

fun4 :: Int 
fun4 = I# 0# 

fun :: String -> String -> (Int, Bool) 
fun = 
    \ _ (w1 :: String) -> 
    (fun4, 
    case readEither6 (run fun3 w1) of _ { 
     [] -> fun2; 
     : x ds -> 
     case ds of _ { 
      [] -> x; 
      : ipv ipv1 -> fun1 
     } 
    }) 

Hinweis, das ist wirklich ein Kommentar und keine Antwort, nur weil ich nicht sicher bin, was genau das Ziel ist, aber der Code würde einen Kommentar nicht passen.

Verwandte Themen