2013-02-22 2 views
7

ja nie rozumiem, dlaczego te dwa podobne listowych dać różne wyniki:Podobne Haskell listowych z różnymi wynikami

Prelude> let t2s n= [ 1/(2*i) | i <- [1,3..n]] 
Prelude> t2s 0 
[0.5] 
Prelude> let t2s n= [ (2*i) | i <- [1,3..n]] 
Prelude> t2s 0 
[] 

Spodziewałem się zarówno do powrotu [] na argumencie 0. Muszę tęsknić za czymś głupim ?!

Odpowiedz

6

Ma to związek z faktem, że

enumFromThenTo 1.0 3.0 0.0 

ocenia się [1.0]. Specyfikacja enumFromThenTo dla Floats znajduje się w sekcji 6.3.4 z http://www.haskell.org/onlinereport/haskell2010/haskellch6.html.

+2

W celu zwiększenia wartości liczb zmiennoprzecinkowych, [a, b..c] kontynuują działanie, dopóki liczby nie przekroczą c + (b-a) /2,0. Na przykład [1.0, 2.0 .. 4.0] to [1.0, 3.0, 5.0]. –

+0

Co stało się z 2.0 i 4.0 w twoim przykładzie? –

+0

@ Code-Guru. Mea culpa. Miałem na myśli [1.0, 3.0 .. 4.0]. Dzięki. –

7

Przede wszystkim zmieniłem nazwę pierwszego t2s na , aby móc załadować oba jednocześnie do ghci. Spójrz na uzyskanymi typów dla każdego z nich:

[ts.hs:2:1-33] *Main> :t t1s 
t1s :: (Enum t, Fractional t) => t -> [t] 
[ts.hs:2:1-33] *Main> :t t2s 
t2s :: (Enum t, Num t) => t -> [t] 
[ts.hs:2:1-33] *Main> 

Zauważ, że t1s zajmuje Fractional argumentu natomiast t2s zajmuje Num. Oznacza to, że w t1s 0, 0 jest rozumiane jako Double. Z drugiej strony interpreter podaje 0, aby być Integer w t2s 0. Ponieważ rodzaj używany do argumentu różni się, zachowanie może się różnić w bardzo zaskakujący sposób. W szczególności należy pamiętać o używaniu tylko typów Integral podczas wymieniania listy, jak w przypadku [1,3..n].

Aby to naprawić, wystarczy podać jawne podpisy typów dla obu funkcji.

+3

Ustawienie domyślne ponownie uderza! Zasadniczo wnioskowanie typu znajduje najbardziej ogólny typ. Problem polega na tym, że literały numeryczne są przeciążone, więc wyrażenie takie jak "t2s 0" jest niejednoznaczne - może być poprawne dla * dowolnego * typu numerycznego! Ponieważ niejednoznaczności takie jak te są powszechne i chcemy mieć możliwość używania Haskella jak kalkulatora, mamy do czynienia z hackowskim sposobem radzenia sobie z nim: [defaulting] (http://www.haskell.org/onlinereport/decls.html#sect4 .3.4). Zasadniczo najpierw próbujemy 'Integer', a następnie wypróbujemy' Double' dla takich wyrażeń. Możesz edytować coś na ten temat w swojej odpowiedzi. –

+0

@ TikhonJelvis Jestem nowicjuszem Haskell i nie wiedziałem o domyślnym terminie, dopóki nie opublikowałeś tego komentarza. Moja tutaj zamieszczona odpowiedź pochodzi od hackowania kodu OP, ponieważ byłem ciekawy różnic. Znalazłem różnice między typami, gdy "' 'przeszedłem ocenę. –

+0

To dobry czas, aby dowiedzieć się o nim jako o każdym :). W pierwszej kolejności przeczytałem o tym także, odpowiadając na pytanie SO. W rzeczywistości w ten sposób zdobyłem całą masę takich smakołyków. –