2015-10-08 2 views
35

Jeśli powiem: let 5 = 10, dlaczego 5 + 1 zwraca 6 zamiast 11?O użytkowniku `let 5 = 10`

+19

Natychmiastowa odpowiedź byłaby „ponieważ nie można przedefiniować co' 5' jest”. Jednak jestem całkiem zaskoczony, pisząc "let 5 = 10", który jest nawet możliwy! – duplode

+3

co możesz zrobić, to 'przeciążać'' + ':' let 1 + 1 = 3 in 1 + 1';) – Carsten

+8

btw: Myślę, że '5' w' let 5 = 10' jest nadal wzorcem (just taki, który nigdy nie jest dopasowany), więc nie będzie niczego wiązał (jak w 'let (x, 5) = (6,6)') – Carsten

Odpowiedz

52

Kiedy mówisz

let 5 = 10 

to nie jest redefinicja 5, to dopasowywanie wzorca, ten sam, który pojawia się, gdy mówisz

foo 5 = undefined 
... foo 10 ... 

Wzór po prostu nie działa, jeśli to kiedykolwiek dopasowane.

W wyrażeniach letowych mecz jest leniwy. Oznacza to, że dopasowanie jest wykonywane tylko wtedy, gdy oceniana jest zmienna związana przez niego. Dzięki temu możemy napisać takie rzeczy, jak

let foo = undefined in 10 

W wyrażeniu żadna zmienna nie jest powiązana, więc wzór nigdy nie jest dopasowany.

Prawdopodobnie takie wzorce bez zmiennych nie mają sensu w wiązaniach let i powinny być wykrywane przez kompilator, ale język nie zabrania ich.

+5

Pocieszające 'let (5, x) = (10, True) w x' dostarcza' *** Wyjątek: : 2: 5-21: Niepowtarzalny wzorzec zawiodły dla wzorca (5, x) '. – pigworker

+3

To jest głupie dla wiązań let, ale nie dla wszystkich: np. 'only5 xs = [5 | 5 <- xs] 'ma sens (jeśli jesteś w porządku z listami' fail'). – user3237465

+0

@ user3237465 tak, miałem na myśli tylko wiązanie let. Aktualizacja. –

15

Zasadniczo

let 5 = 10 in ... 

jest równoważna

case 10 of ~5 -> ... 

Zanotować ~, który oznacza leniwy lub niepodważalny wzór. Jest to wzorzec, który pasuje do wszystkiego, a to odkłada mecz do punktu, w którym faktycznie żądana jest pewna zmienna. Nie ma żadnych zmiennych w wzorze 5, więc nic się nie dzieje.

Ta narożna obudowa jest zupełnie bezużyteczna i prawdopodobnie kompilator powinien wysłać tutaj ostrzeżenie.

celu wyjaśnienia znaczenia lazy wzorów, za to:

case f 3 of 
    (x,y) -> g 10 x y 

tutaj f 3 oceniano najpierw (do WHNF), odsłaniając konstruktora pary. Następnie x,y są powiązane z (jeszcze nie ocenionymi) składnikami pary. Na koniec, oblicza się g 10, wynik jest stosowany do x (który może być teraz wymagany), a następnie do y (co może spowodować, że wymagany będzie x lub y).

porównania

case f 3 of 
    ~(x,y) -> g 10 x y 

nie rozpocznie z oceny f 3. Zamiast tego x jest związany z nieocenionym fst (f 3) i y jest związany z nieocenionym snd (f 3). Zamiast tego zaczynamy od oceny g 10. Następnie stosujemy to do x: może to wymagać x, wywołując ocenę f 3. Następnie stosujemy wynik do y, powodując podobną ocenę.Większość implementacji będzie faktycznie udostępnić wynik f 3 między x i y tak, że zostanie obliczona co najwyżej raz.

1

As @ n.m. mówi, że masz dopasowywanie do wzorca. Oto kilka przykładów.

wzorzec pasuje może uda

Prelude> let (a, 10) = (15, 10) in a 
15 

lub nie.

Ponieważ Haskell jest leniwy, Twój kod się powiedzie, jeśli nie użyjesz wartości wynikowej. To jest w zasadzie to, co robisz:

Prelude> let (a, 10) = (15, 15) in "Something else" 
"Something else" 

uwaga, że ​​typy muszą jeszcze sprawdzić:

Prelude> let (a, 10, 999) = (15, 15) in "Something else" 

<interactive>:7:20: error: 
    • Couldn't match expected type ‘(t, Integer, Integer)’ 
        with actual type ‘(Integer, Integer)’ 
    • In the expression: (15, 15) 
     In a pattern binding: (a, 10, 999) = (15, 15) 
     In the expression: let (a, 10, 999) = (15, 15) in "Something else" 
    • Relevant bindings include a :: t (bound at <interactive>:7:6) 
+0

" Ponieważ Haskell jest leniwy, twój kod się powiedzie, jeśli nie użyjesz wartości wynikowej "- Warto wspomnieć, że ważne jest również to, aby" pozwolić " wiązania domyślnie pasują leniwie. 'case (15, 15) z {(a, 10) ->" Coś innego "}' zawiesza się, a 'case (15, 15) z {~ (a, 10) ->" Coś innego "} (które , dzięki leniwemu dopasowaniu [jest równoważne Twojemu trzeciemu przykładowi] (https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-440003.12)) się udaje. – duplode

+0

@duplode, myślę, że leniwe domyślne ustawienie w 'let' i' where' było złym pomysłem, i jest to powód, dla którego czasami mogą być mylące wzorce. – dfeuer

+0

@dfeuer Co z wiązaniem z nieskończoną listą? Na przykład 'let nats = [1 ..] w takeWhile isOkay nats' – Teodor