2016-07-12 5 views
2

Ich bin herumalbern mit Linsen und Prismen und ich bin ein bisschen in die Unkräuter geraten. Ich mag folgende in Vorlage Haskell schreiben, aber wie ist es nicht kompiliert:Wie kann ich (Falte s a) von Control.Lens ein Monoid machen?

data Suit = Spade | Heart | Diamond | Club 
makePrisms ''Suit 
blackSuits = _Spade <> _Club 

Alles, was ich weiß, über Linsen und Prismen (sowie Kommentare in der Getter Dokumentation) legt nahe, dass _Spade <> _Club eine gültiges Fold Suit() sein sollte . Aber ghc kann den obigen Code nicht kompilieren; Es beschwert sich über mehrere mehrdeutige Instanzen. GHCI gibt mir die folgende Art Signatur für _Spade <> _Club:

_Spade <> _Club 
    :: (Applicative f, Monoid (p Suit (f Suit)), Choice p) => 
    p() (f()) -> p Suit (f Suit) 

Und durch p mit (->) ersetzen kann ich diese Art zu

(Applicative f, Monoid (f Suit)) => (() -> f()) -> Suit -> f Suit 

Der einzige Unterschied zwischen dem, entspannen und Fold Suit() ist, dass letztere (Applicative f, Contravariant f) => ... stattdessen hat der Monoid (f Suit) Beschränkung. Wenn ich auf Contravariant nachlese, sehe ich Aussagen, dass (Applicative f, Contravariant f) zusammen implizieren, dass f tatsächlich Const r für einige Monoid r ist. Dies scheint darauf hinzudeuten, dass der obige Typ tatsächlich eine Teilmenge von Fold Suit() ist. Aber wenn ich versuche blackSuits :: Fold Suit() meinen Code hinzufügen bekomme ich

Could not deduce (Monoid (f Suit)) arising from a use of ‘<>’ 
from the context (Contravariant f, Applicative f) ... 

ich Ähnliche Fehler, wenn ich versuche, nur Monoide auf Falten zu definieren, anstatt mit Prismen zu starten. Nichts, was ich getan habe, um Fold s a eine Monoid zu machen und den Compiler zu bestehen. Gibt es eine Möglichkeit, dies zum Funktionieren zu bringen?

Antwort

4

Wenn Sie den Blick auf Fold Unterschrift:

type Fold s a = forall f. (Contravariant f, Applicative f)=> (a -> f a) -> s -> f s 

es sagt, es ist für alle f die Contravariant und Applicative sind zu arbeiten hat. Wenn Sie zwei Faltungen unter Verwendung von <> kombinieren, erfordert die Instanz Semigroup für die Funktionen instance Semigroup b => Semigroup (a -> b), dass f sSemigroup ist. Das bedeutet, es wird keine Überprüfung mehr als Fold geben. Die meisten (alle?) Funktionen, die in lens eine Faltung ausführen, akzeptieren dies jedoch immer noch, da sie eine Getting r s a = (a -> Const r a) -> s -> Const r s nehmen, für die diese Prüfung einen Typ gibt.

Es gibt ein paar Dinge, die Sie tun können. Sie könnten die Fold newtype verwenden, die ihre eigene Monoid Instanz hat:

> :set -XTemplateHaskell 
> import Control.Lens 
> import Data.Semigroup 
> data Suit = Spade | Heart | Diamond | Club; makePrisms ''Suit 
> let blackSuitsFold = runFold $ Fold _Spade <> Fold _Club :: Fold Suit() 

Oder Sie könnten „Klon“ der Falte:

> let cloneFold = foldring . foldrOf 
> let blackSuitsClone = cloneFold $ _Spade <> _Club :: Fold Suit() 

oder, wenn Sie es nicht brauchen eine Fold Sie zu sein kann Getting Synonym verwenden, das in den meisten Fällen das gleiche funktionieren würde:

> let blackSuitsGetter = _Spade `mappend` _Club :: Monoid r => Getting r Suit() 
> has blackSuitsGetter Spade 
True 
+0

Ah, das ist, was "verdinglichte" Falten sind für! Vielen Dank! –

Verwandte Themen