Espressioni lambda senza parametri in Haskell e / o lambda calcolo

8

In linguaggi desiderosi come Scheme e Python, puoi usare un'espressione lambda senza parametri per ritardare la valutazione, ad es. in Scheme (Chicken Scheme):

#;1> (define (make-thunk x) (lambda () (+ x 1)))
#;2> (define t (make-thunk 1))
#;3> (t)
2

Nella riga 2, t è associato all'espressione non valutata (lambda () (+ 1 1)) , che viene quindi valutata a 2 nella riga 3.

Allo stesso modo, in Python:

>>> def make_thunk(x): return lambda: x + 1
... 
>>> t = make_thunk(1)
>>> t()
2

Usando questa tecnica si può implementare una valutazione pigra in un linguaggio appassionato.

Quindi, mi aspettavo che Haskell non avrebbe espressioni lambda senza parametri perché il linguaggio è già pigro e non è necessario creare espressioni ritardate. Con mia sorpresa, ho scoperto che in Haskell è possibile scrivere l'espressione lambda

\() -> "s"

che può essere applicato solo al valore () in questo modo:

(\() -> "s") ()

dare il risultato

"s"

Applicando questa funzione a qualsiasi argomento diverso da () si genera un'eccezione (almeno per quanto ho potuto vedere durante i miei test). Questo sembra diverso dalla valutazione ritardata in Scheme e Python, perché l'espressione ha ancora bisogno di un argomento da valutare. Quindi cosa significa un'espressione lambda senza variabili (come \() -> "s" ) in Haskell e cosa può essere utile?

Inoltre, sarei curioso di sapere se espressioni lambda parametriche simili esistono in una varietà di lambda-calculus.

    
posta Giorgio 23.09.2014 - 23:07
fonte

3 risposte

12

Bene, le altre risposte riguardano cosa \() -> "something" significa in Haskell: una funzione unaria che prende come argomento () .

  • Che cos'è una funzione senza argomenti? - Un valore. In realtà, a volte può essere utile pensare a variabili come funzioni nullarie che valutano il loro valore. Il let -syntax per una funzione senza argomenti (che in realtà non esiste) finisce per darti un legame variabile: let x = 42 in ...

  • Il lambda calcolo ha funzioni nullarie? - No. Ogni funzione richiede esattamente un argomento. Tuttavia, questo argomento può essere un elenco o la funzione può restituire un'altra funzione che accetta l'argomento successivo. Haskell preferisce quest'ultima soluzione, in modo che a b c sia in realtà due chiamate di chiamate ((a b) c) . Per simulare le funzioni null, devi passare un valore di segnaposto inutilizzato.

risposta data 23.09.2014 - 23:30
fonte
8

Stai interpretando male ciò che () significa in Haskell. Non è la mancanza di un valore, è piuttosto il valore solo del tipo Unità (il tipo stesso a cui fa riferimento un insieme vuoto di parentesi () ).

Poiché lambdas può essere costruito per usare la corrispondenza dei pattern, l'espressione lambda \() -> "s" dice esplicitamente "crea una funzione anonima, aspettando un input che corrisponda al pattern () ". Non ha molto senso farlo, ma è certamente permesso.

Puoi anche usare pattern matching con lambda in altri modi, ad esempio:

map (\(a, b) -> a + b) [(1,2), (3,4), (5,6)] -- uses pattern matching to destructured tuples

map (\(Name first _) -> first) [Name "John" "Smith", Name "Jane" "Doe"] -- matches a "Name" data type and its first field

map (\(x:_) -> x) [[1,2,3], [4,5,6]] -- matches the head of a list
    
risposta data 23.09.2014 - 23:14
fonte
1

() -> "s" è una funzione lambda che accetta l'argomento one :

ghci> :t (\() -> "s")
(\() -> "s") :: () -> [Char]

() , la tupla vuota (talvolta chiamata Unità), è un tipo completo in Haskell. Ha solo un membro (ignorando _|_ *), che è anche scritto come () . Guarda la definizione di () :

data () = ()

Questo significa che il modulo sul lato sinistro della tua espressione lambda è sintatticamente un pattern match che corrisponde a () , l'unico membro del tipo () . C'è solo un modo valido per chiamarlo (che è quello di fornire () come argomento) perché c'è solo un membro valido del tipo () .

Tale funzione non è molto utile in Haskell, perché i termini predefiniti vengono comunque calcolati pigramente, come hai osservato nella tua domanda.

Per una spiegazione molto più dettagliata, consulta questa risposta .

* _|_ è chiamato "bottom" o "undefined". Digita sempre i controlli, ma si blocca il programma. Il classico esempio di come ottenere un _|_ è let x = x in x .

    
risposta data 23.09.2014 - 23:14
fonte

Leggi altre domande sui tag