2

Ich verstehe, dass it's impossible to pattern match functions in Haskell, und ich verstehe voll und ganz warum. Ich habe jedoch zwei eng verwandte Fragen. Erstens, in Fällen, in denen Sie Funktionen zur späteren Verwendung teilweise anwenden möchten, gibt es eine Möglichkeit, die Rückgabe zu definieren und zu erfassen, wenn es sich um ein Tupel handelt? Oder liege ich falsch, und das versucht immer noch, Funktionen unter meiner Nase zusammenzufassen?Gibt es eine Möglichkeit, ein Tupel von Funktionen höherer Ordnung in Haskell zu erfassen?

Angenommen, ich versuche, den Quotienten und den Rest eines Wertes mit verschiedenen Vielfachen von zehn zu erhalten. Wie würde ich dann so etwas schreiben?

q, r :: Integral a => a -> a 
(q, r) = (12345 `quotRem`) 

Mir ist klar, hier gibt es getrennte Funktionen, die vorhanden sind, so konnte ich diese stattdessen tun:

q, r :: Integral a => a -> a 
q = (12345 `quot`) 
r = (12345 `rem`) 

Allerdings, das ist ein sehr spezifischer Fall, und es gibt unbegrenzte andere Beispiele von Funktionen, die Rückkehr Tupel, die man verallgemeinern könnte. Zum Beispiel eine Funktion, die die Anzahl der Evens und Odds in einer Liste zurückgibt.

evens, odds :: Integral a => [a] -> Int 
(evens, odds) = (length . (filter even), length . (filter odd)) 

Dies führt mich zu meiner zweiten Frage. Das obige funktioniert in GHCi gut.

Prelude> let (evens, odds) = (length . (filter even), length . (filter odd)) 
Prelude> :t evens 
evens :: Integral a => [a] -> Int 
Prelude> evens [1..10] 
5 

Was ist noch verwirrender ist es funktioniert sogar durch „Pattern-Matching“ in der gleichen Art und Weise, die ich mit (q, r) am Anfang gespielt wurde:

Prelude> let evensOdds = (length . (filter even), length . (filter odd)) 
Prelude> :t evensOdds 
evensOdds :: (Integral a1, Integral a) => ([a1] -> Int, [a] -> Int) 
Prelude> let (ev,od) = evensOdds 
Prelude> :t ev 
ev :: Integral a1 => [a1] -> Int 
Prelude> ev [1..10] 
5 

Es funktioniert auch ganz gut in einem tatsächlichen Datei in GHCi geladen, auch wenn (evens, odds) nicht. Warum sind diese beiden verschieden und warum arbeitet die zweite überhaupt in GHCi, wenn sie nicht normal funktioniert? Kann das, was hier anders ist, irgendwie genutzt werden?

Antwort

5

Sie haben nie eine Übereinstimmung mit einer Funktion gefunden. Sie pattern immer auf dem Paar-Konstruktor (,). Ihr (even, odds) Beispiel

(evens, odds) = (length . (filter even), length . (filter odd)) 

funktioniert genauso wie

(first, second) = (x, y) 

Es spielt keine Rolle, welche Art x und y an diesem Punkt haben.


Ihr (q, r) Beispiel funktioniert nicht aufgrund quotRem ‚s-Typ. Sagen wir es erinnern und vergleichen ihn mit (q, r) ‚s Typ:

quotRem  :: Integral n => n -> n -> (n  , n) 
quotRem 12345 :: Integral n =>  n -> (n  , n) 
(q, r)  :: Integral n =>   (n -> n, n -> n) 

Wie Sie das Paar (q, r) sehen können,‘ unterscheidet sich von Typ quotRem ‚s ein. Dennoch ist es möglich, Ihre Funktion zu schreiben:

pairify :: (a -> (b, c)) -> (a -> b, a -> c) 
pairify f = (fst . f, snd . f) 

(q,r) = pairify (quotRem 12345) 

Aber wie Sie sehen können wir von pairify nicht zu viel gewinnen.By the way, partition von Data.List bietet Ihre (even, odds) Funktionalität:

(even, odds) = pairify (partition even) 
3

Blick auf die Art von (12345 `quotRem`):

Integral a => a -> (a, a) 

Es ist eine einzige Funktion, die ein Tupel zurück. Wenn Sie diese in ein Tupel von Funktionen machen möchten, können Sie es mit fst komponieren kann und snd:

(q, r) = (fst . f, snd . f) 
    where f = (12345 `quotRem`) 

Wenn Sie dies in einem Punkt freien Art und Weise tun wollen, ist eine Möglichkeit, die &&& combinator zu verwenden, um von Control.Arrow. Seine vollständig allgemeine Art ist:

Arrow a => a b c -> a b d -> a b (c, d) 

Specialized auf den -> Pfeil, das ist:

(b -> c) -> (b -> d) -> b -> (c, d) 

So dauert es zwei Funktionen, die jeweils einen Wert vom Typ unter b und kehren beide ihre Ergebnisse (die Typen c und d) in einem Tupel. Also hier können Sie etwas tun:

split = (fst .) &&& (snd .) 
(q, r) = split (12345 `quotRem`) 

Während, wenn man sich die Art von (length . filter even, length . filter odd), es ist ein Tupel bereits,

(Integral a, Integral b) => ([a] -> Int, [b] -> Int) 

Weswegen natürlich können Sie dieses Tupel denaturiert, zu binden, evens und odds.

Verwandte Themen