13 Stimmen

Currying außerhalb der Reihenfolge in Haskell

Gibt es eine elegante Notation für Currying die Argumente einer Funktion außer der Reihe in Haskell?

Wenn Sie zum Beispiel 2 durch alle Elemente einer Liste dividieren wollen, können Sie schreiben

map ((/) 2) [1,2,3,4,5]

Um jedoch alle Elemente einer Liste zu teilen, müssen Sie offenbar eine anonyme Funktion definieren

map (\x -> x/2) [1,2,3,4,5]

Anonyme Funktionen werden in komplexeren Fällen schnell unhandlich. Ich bin mir bewusst, dass in diesem Fall map ((*) 0.5) [1,2,3,4,5] gut funktionieren würde, aber ich bin daran interessiert zu wissen, ob Haskell eine elegantere Möglichkeit hat, die Argumente einer Funktion außerhalb der Reihenfolge aufzurufen?

17voto

In diesem speziellen Fall:

Prelude> map (/2) [1..5]
[0.5,1.0,1.5,2.0,2.5]

Sie können einen Infix-Operator nicht nur als gewöhnliche Präfix-Funktion verwenden, sondern ihn auch teilweise in Infix-Form anwenden. Das erste Beispiel lässt sich also besser schreiben als map (2/) [1..5]

Außerdem gibt es flip was nicht ganz so elegant ist, aber immer noch die beste Option für gewöhnliche Funktionen ist (wenn man sie nicht über Backticks in Infix verwandeln will):

Prelude> let div' = (/)
Prelude> div' 2 1
2.0
Prelude> flip div' 2 1
0.5

2voto

fuz Punkte 82245

Bei der zweiten ist das Lambda unnötig, verwenden Sie einfach like:

map (/2) [1..5]

Die Form (/2) bedeutet einfach, dass Sie auf den zweiten Parameter eines Operators zugreifen wollen. Es ist auch mit dem ersten Argument möglich (2/) . Dies wird als Abschnitt und ist ein wirklich nützlicher Hack, nicht nur beim Code-Golf. Sie können es auch in Präfix-Funktionen verwenden, wenn Sie sie infix verwenden:

map (`div` 2) [1..5]

In schwierigeren Fällen, wie bei 3 oder mehr Argumenten, sollten Sie Lambdas verwenden, da dies in den meisten Fällen besser lesbar ist.

2voto

gawi Punkte 13510

Ich denke, Sie suchen nach einer allgemeinen Lösung, wie die cut im Schema. Oder?

Es gibt die flip Funktion, die die ersten 2 Argumente umkehren einer Funktion. Möglicherweise gibt es andere Funktionen, die eine ähnliche Aufgabe erfüllen (ich kenne mich mit Haskell nicht so gut aus... noch nicht).

0voto

Gaius Punkte 2494

Ich bin auf eine sehr ähnliches Problem und ich konnte keine elegante Lösung finden, außer eine Hilfsfunktion dafür zu verwenden:

dbfunc f b c = (\a -> liftIO $ f a b c)
deleteAllRows = do
  ask >>= dbfunc run "delete from t1" []

Zumindest ist dieses Muster in HDBC so verbreitet, dass dbfunc wiederverwendbar ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X