10 Stimmen

Versuch, den Funktionsanwendungsoperator in Haskell zu verstehen

Ich versuche, den Funktionsanwendungsoperator ($) in Haskell zu verstehen.

Ich arbeite die Beispiele in "Learn You a Haskell" durch und dachte, ich hätte das folgende Beispiel verstanden:

Prelude> map ($ 3) [(+4), (*10), (^2), sqrt]
[7.0,30.0,9.0,1.7320508075688772] 

Dann habe ich die folgende Variante versucht, die auch gut funktioniert hat:

Prelude> map ($ 3) [(+4), (*10), (\x -> x^2), sqrt]
[7.0,30.0,9.0,1.7320508075688772]

Zuletzt habe ich versucht, die dritte Funktion in der Liste wie folgt zu ändern, was einen Fehler erzeugt:

Prelude> map ($ 3) [(+4), (*10), (\x -> 2^x), sqrt] 
:53:38:
    Ambiguous type variable `b0' in the constraints:
      (Floating b0)
        arising from a use of `sqrt' at :53:38-41
      (Integral b0) arising from a use of `^' at :53:33
      (Num b0) arising from the literal `3' at :53:8
    Probable fix: add a type signature that fixes these type variable(s)
    In the expression: sqrt
    In the second argument of `map', namely
      `[(+ 4), (* 10), (\ x -> 2 ^ x), sqrt]'
    In the expression: map ($ 3) [(+ 4), (* 10), (\ x -> 2 ^ x), sqrt]
Prelude> 

Es scheint so, als ob die letzte sqrt Funktion irgendwie mit dem vorherigen Listenelement verbunden ist, da die folgende Variante gut funktioniert:

Prelude> map ($ 3) [(+4), (*10), (\x -> 2^x)]
[7,30,8]

Kann mir jemand erklären, was hier los ist?

17voto

Daniel Fischer Punkte 178428

Die Art des verwendeten Potenzierungsoperators ist

(^) :: (Num a, Integral b) => a -> b -> a

so wenn du \x -> 2^x verwendest, erhältst du eine Integral Einschränkung für die 3. Aber sqrt legt eine Floating Einschränkung fest. Deshalb muss der Typ der 3 erfüllen

3 :: (Integral t, Floating t) => t

aber es gibt keine Instanz für beide in der Standardtypenliste, die Integer und Double ist, daher schlägt die Standardisierung fehl und es bleibt eine unklare Typvariable übrig.

Als du \x -> x^2 hattest, gab es nur eine Num Einschränkung von den ersten Funktionen und Floating von sqrt, daher wurde der Typ auf Double standardisiert.

Du kannst es funktionieren lassen, wenn du

(**) :: Floating a => a -> a -> a

als deinen Potenzierungsoperator verwendest, dann kann der Typ wieder auf Double standardisiert werden.

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