2012-06-07 16 views
9

Ich habe versucht, ein Haskell-Beispiel zu konvertieren, ich kam früher zu Scalaz. Das ursprüngliche Beispiel war:Anwendbare Instanz für ein Tupel mit Monoid und Funktion innerhalb

("Answer to the ", (*)) <*> ("Ultimate Question of ", 6) <*> ("Life, the Universe, and Everything", 7) 

Welche, soweit ich in der Lage bin zu verstehen, nutzt this Instanz. Obwohl, ich habe sieht für eine Instanz

scala> ("Answer to the ", ((_: Int) * (_: Int)) curried) |@| ("Ultimate Question of ", 6) |@| ("Life, the Universe, and Everything", 7) tupled 
res37: (java.lang.String, (Int => (Int => Int), Int, Int)) = (Answer to the Ultimate Question of Life, the Universe, and Everything,(<function1>,6,7)) 

, und es scheint be there (wieder, soweit ich in der Lage bin zu verstehen):

wird es nicht scalaz buchstäblich umgewandelt.

Also, die Frage ist: Warum funktioniert es nicht so? Oder was habe ich vermisst/nicht richtig verstanden?

+1

Dieser Code sendet tatsächlich an die anwendungsspezifische Instanz für Tupel. Das wiederum verwendet den monoiden 'mappend' für Listen (Concentation). Also ist es die Funktionszusammensetzung der zweiten Komponente des Tupels, mit der Liste der Konkatentation des ersten Teils. –

Antwort

5

Scalaz entspricht Control.Applicative 's <*> wird auch <*> genannt, obwohl es seine Argumente in umgekehrter Reihenfolge verwechselt. So sind die folgenden Werke:

val times = ((_: Int) * (_: Int)) curried 
val a = "Answer to the " 
val b = "Ultimate Question of " 
val c = "Life, the Universe, and Everything" 

(c, 7) <*> ((b, 6) <*> (a, times)) 

Oder, wie ich als Antwort auf Ihren Kommentar bemerkt haben, können Sie den folgenden verwenden, wenn Sie mit |@| haften möchten:

(a -> times |@| b -> 6 |@| c -> 7)(_ apply _ apply _) 

Ich persönlich bevorzuge die <*> Version, auch wenn es sich rückwärts anfühlt.


Wir gehen durch, was in etwas ausführlichen abgeht. Vor allem brauchen Sie nicht die volle Leistung von Applicative hier - Apply wird tun. Wir können die Apply Instanz für Tupel erhalten mit implicitly:

scala> val ai = implicitly[Apply[({type λ[α]=(String, α)})#λ]] 
ai: scalaz.Apply[[α](java.lang.String, α)] = [email protected] 

Jetzt können wir unser erstes Tupel auf die zweite Anwendung:

scala> :t ai(a -> times, b -> 6) 
(java.lang.String, Int => Int) 

Und das Ergebnis an die dritte:

scala> :t ai(ai(a -> times, b -> 6), c -> 7) 
(java.lang.String, Int) 

Was wir wollen:

scala> ai(ai(a -> times, b -> 6), c -> 7)._1 
res0: java.lang.String = Answer to the Ultimate Question of Life, the Universe, and Everything 

scala> ai(ai(a -> times, b -> 6), c -> 7)._2 
res1: Int = 42 

Die <*> Methode auf MA wickelt das nur ein wenig schöner.

+0

Danke, funktioniert wie es soll. Übrigens, haben Sie eine Idee, wie Sie dies mit dem ApplicativeBuilder tun können und ob es auf diese Weise besser aussieht? – folone

+1

Sicher, Sie könnten etwas tun wie '(a -> mal | @ | b -> 6 | @ | c -> 7) (_ apply _ apply _)', aber ich denke, die '<*>' Version ist schöner. –

+0

Ja, das funktioniert. Ich wurde durch die Tatsache irregeführt, dass 'tupled' das Monoid aufgeklebt hat, also dachte ich, es würde die Funktion auch anwenden. – folone