In eifrigen Sprachen wie Scheme und Python können Sie einen Lambda-Ausdruck ohne Parameter verwenden, um die Auswertung zu verzögern, z. B. in Scheme (Chicken Scheme):
#;1> (define (make-thunk x) (lambda () (+ x 1)))
#;2> (define t (make-thunk 1))
#;3> (t)
2
In Zeile 2 t
wird an den nicht bewerteten Ausdruck gebunden, der (lambda () (+ 1 1))
dann 2
in Zeile 3 ausgewertet wird .
Ähnlich in Python:
>>> def make_thunk(x): return lambda: x + 1
...
>>> t = make_thunk(1)
>>> t()
2
Mit dieser Technik kann man eine verzögerte Auswertung in einer eifrigen Sprache implementieren.
Ich hatte also erwartet, dass Haskell keine Lambda-Ausdrücke ohne Parameter haben würde, da die Sprache bereits faul ist und keine verzögerten Ausdrücke erstellt werden müssen. Zu meiner Überraschung fand ich heraus, dass es in Haskell möglich ist, den Lambda-Ausdruck zu schreiben
\() -> "s"
was nur auf den ()
Wert wie folgt angewendet werden kann :
(\() -> "s") ()
das Ergebnis geben
"s"
Das Anwenden dieser Funktion auf ein anderes Argument als das ()
Auslösen einer Ausnahme (zumindest soweit ich dies während meiner Tests sehen konnte). Dies scheint sich von der verzögerten Auswertung in Scheme und Python zu unterscheiden, da der Ausdruck noch ein zu bewertendes Argument benötigt. Was bedeutet ein Lambda-Ausdruck ohne Variablen (wie \() -> "s"
) in Haskell und wofür kann er nützlich sein?
Ich wäre auch neugierig zu wissen, ob ähnliche parameterlose Lambda-Ausdrücke in (einer Vielzahl von) Lambda-Berechnungen existieren.
()
Auslösen einer Ausnahme ..." Verursacht das Programm eine Ausnahme oder beschwert sich der Compiler darüber, dass der Code keine Prüfung eingibt?Antworten:
Nun, die anderen Antworten decken ab, was
\() -> "something"
in Haskell bedeutet: eine unäre Funktion, die()
als Argument dient.Was ist eine Funktion ohne Argumente? - Ein Wert. Tatsächlich kann es gelegentlich nützlich sein, sich Variablen als Nullfunktionen vorzustellen, die auf ihren Wert ausgewertet werden. Die
let
-syntax für eine Funktion ohne Argumente (die eigentlich nicht existiert) gibt Ihnen eine Variablenbindung:let x = 42 in ...
Hat der Lambda-Kalkül Nullfunktionen? - Nein. Jede Funktion benötigt genau ein Argument. Dieses Argument kann jedoch eine Liste sein, oder die Funktion kann eine andere Funktion zurückgeben, die das nächste Argument verwendet. Haskell bevorzugt die letztere Lösung, das
a b c
sind also eigentlich zwei Funktionsaufrufe((a b) c)
. Um Nullfunktionen zu simulieren, müssen Sie einen nicht verwendeten Platzhalterwert übergeben.quelle
(f)
konzeptionell eine Einzelelementliste mit einem Kopfwert von'f
und einem Null-Schwanz - also könnencons
wir ihn als schreiben(cons 'f '())
. Dieser Schwanz ist die Liste, die (konzeptionell) als Argument verwendet wird, und es spielt keine Rolle, dass nil die leere Liste darstellt. Der Unterschied zwischen Lisp und Haskell besteht darin, dass letzteres implizites Currying hat, so dass der Ausdruck(f)
verschiedene Dinge bedeutet()
(wie es bei MLs der Fall ist) angeben müssen oder ob Sie dies nicht wissentlich tun (wie dies bei Lisps oder C-ähnlichen Sprachen der Fall ist), spielt keine Rolle.Sie interpretieren falsch, was
()
in Haskell bedeutet. Es ist nicht das Fehlen eines Wertes, sondern der einzige Wert des Einheitentyps (der Typ selbst, auf den durch einen leeren Satz von Klammern verwiesen wird()
).Da Lambdas so konstruiert werden können, dass sie den Mustervergleich verwenden,
\() -> "s"
sagt der Lambda-Ausdruck explizit "Erstellen Sie eine anonyme Funktion und erwarten Sie eine Eingabe, die dem()
Muster entspricht". Es macht nicht viel Sinn, es zu tun, aber es ist auf jeden Fall erlaubt.Sie können den Mustervergleich mit Lambdas auch auf andere Weise verwenden, zum Beispiel:
quelle
Unit
wird auch()
in Haskell geschrieben.const
, die nimmt jede Eingabe und wandelt sie alle in den gleichen Wert).() -> "s"
ist eine Lambda-Funktion, die ein Argument akzeptiert:()
, das leere Tupel (manchmal auch als Einheit bekannt), ist ein vollwertiger Typ in Haskell. Es hat nur ein Mitglied (ignoriert_|_
*), das auch als geschrieben ist()
. Schauen Sie sich die Definition von()
:Dies bedeutet, dass das Formular auf der linken Seite Ihres Lambda-Ausdrucks syntaktisch eine übereinstimmende Musterübereinstimmung ist
()
, das einzige Mitglied des Typs()
. Es gibt nur eine gültige Möglichkeit, es aufzurufen (nämlich()
als Argument anzugeben), da es nur ein gültiges Mitglied des Typs gibt()
.Eine solche Funktion ist in Haskell nicht sehr nützlich, da Begriffe standardmäßig ohnehin träge ausgewertet werden, wie Sie in Ihrer Frage festgestellt haben.
Eine ausführlichere Erklärung finden Sie in dieser Antwort .
*
_|_
heißt "bottom" oder "undefined". Es prüft immer die Typen, stürzt aber Ihr Programm ab. Das klassische Beispiel, wie man ein bekommt,_|_
istlet x = x in x
.quelle