2016-07-23 24 views
1

Von this answer lernt man, wie man die Funktion \x y z -> f x (g y z) sinnlos in Haskell implementiert, wo f und g Funktionen sind. Und meine Frage istWie kann man f (g x) (h x) punktfrei in Haskell implementieren?

Wie schreibe ich die Funktion \x -> f (g x) (h x) in einer pointfree Weise in Haskell? Hier sind fgh Funktionen, für die f (g x) (h x) definiert ist.

Die Idee, die ich derzeit im Auge habe, ist etwas wie folgt.

uncurry f (mapTuple ($ x) (g, h)) 

Aber mehrere Versuche zeigen, dass dies irreführend ist; selbst der Teil map ($ x) [g, h] ist verdächtig: Was, wenn g und h unterschiedliche Bereiche haben?

Darüber hinaus ist Lesbarkeit nicht zu viel ein Problem hier.

Jede Hilfe wird herzlichst geschätzt.

+1

Das ist nur 'liftA2 f g h '. – melpomene

+0

Danke für den Vorschlag. Aber ich habe Kopfschmerzen zu verstehen, was 'applicative' ist. Vielleicht auch anders, ohne "Applicative" zu sein? Danke immer noch. :) – awllower

+4

Sicher: 'liftM2 f g h' :-) – melpomene

Antwort

3

Als melpomene vorgeschlagen, entspricht \x -> f (g x) (h x)liftM2 f g h.

Wenn Sie Fragen haben, wie Sie Haskell Code in Pointfree Haskell Code konvertieren, können Sie einfach Pointfree.io versuchen.

Es ist ein großes Werkzeug, das kann man oft sagen, wenn sie nicht pointfree Code zu verwenden, da es manchmal völlig unleserlich geht :-)

enter image description here

+0

Danke für die Antwort und diese interessante Website. :) – awllower

+2

Verwenden Sie 'liftA2' besser als' liftM2', letzteres ist seit dem AMP eher veraltet. – leftaroundabout

+0

Sie können auch das Befehlszeilenprogramm 'pointfree' verwenden (und optional Bindings schreiben, um es in ghci-Sitzungen zu integrieren): https://hackage.haskell.org/package/pointfree –

6

Die arrow Version wäre

uncurry f . (g &&& h) 

oder

(g &&& h) >>> uncurry f 

Als Diagramm:

 g ──── 
     ╱   ╲ 
──── &&&  >>> uncurry f ─── 
     ╲   ╱ 
     h ──── 
+0

Danke für den Code. Jetzt werde ich versuchen, auch ein paar Pfeile zu lernen. :) – awllower

2

Applicative Stil

f <$> g <*> h 

Control.Compose

join ((g ~> h ~> id) f) 

Data.Function.Meld

join (f $* g $$ h *$ id) 

Data.Function.Tacit

lurryA @N1 (f <$> (g <$> _1) <*> (h <$> _1)) 
lurryA @N4 (_1 <*> (_2 <*> _4) <*> (_3 <*> _4)) f g h 
+0

Nach einer langen Zeit habe ich endlich, was dieser Code sagt: 'f <$> g <*> h '. Ich denke, es ist kein anderes als 'ap (f. G) h'. In jedem Fall, danke für solche nützliche Informationen. – awllower

+1

@awllower checken Sie die "Intuitionen" aus, die ich hier http://stackoverflow.com/a/34536499/260584 gepostet habe, die eine direkte Möglichkeit anbieten, über Applicative auf Funktionen nachzudenken. Beachten Sie auch, dass '<$>' ist '.',' <*> 'ist der Lambda-Kalkül-Kombinator S, und" rein "ist der Kombinator K (das ist" const "). – erisco

0

Dies dient nur dazu, die Antworten in den Kommentaren zu sammeln und in Reihenfolge zu bringen. Nach den Abstraktion-Eliminierungsverfahren in dem Link in dem Kommentar von @ PetrPudlák können wir auch

S (S (K f) (S (K g) I)) (S (K h) I), 

oder nach eta Reduktion,

S (S (K f) g) h, 

wo

S x y z = x z (y z) 
K x y = x 

schreiben Speziell in Haskell, dank @melpomene für den Hinweis darauf, wird die Rolle von S von ap und vongespieltvon const. Deshalb können wir

ap (ap (const f) g) h 

In der Tat schreiben wir weiter reduzieren:

ap (const f) g = f . g 

So können unsere Funktion geschrieben werden als:

ap (f . g) h 

Wenn zu Applicative Stil übersetzt, so erhalten wir:

f <$> g <*> h 

Dann kann dieser systematische Ansatz auf alle Lambda-Terme angewendet werden und gibt den Punkt-freien Stil. :)