2013-04-03 7 views
8

Je sais

$ :: (a->b) -> a -> b 
f $ x = f x 

Intuitivement il me semble, comme pour dire 1. $ retarde l'évaluation de la fonction à sa gauche 2. évalue ce qui est à son droit 3. nourrit le résultat de son gauche à sa droite.

Et il est parfaitement logique pour moi,

ghci> length $ [1..5] 
5 
ghci> ($) length [1..5] 
5 

Ce que je ne comprends pas pourquoi,

ghci> ($ [1..5]) length 
5 

A en juger par le type de $, n'est pas que son (premier) l'argument devrait être une fonction?

+13

Il ne s'agit pas de '($)', mais des sections d'opérateur. – phg

+9

'$' * ne retarde pas l'évaluation de la fonction à gauche. Vous pouvez le confondre avec '$!', Ce qui force l'évaluation partielle de l'argument à sa droite avant de l'envoyer à la fonction à sa gauche. – dave4420

+0

C'est la syntaxe "section" au travail. http://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-300003.5 –

Répondre

15

Ceci a à voir avec l'analyse. Dans Haskell, vous pouvez écrire (op arg)op est un opérateur infixe. Ce n'est pas la même chose que ((op) arg). Et vous pouvez aussi écrire (arg op)! Par exemple:

GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help 
Prelude> :t (+ 4) 
(+ 4) :: Num a => a -> a 
Prelude> :t (4 +) 
(4 +) :: Num a => a -> a 

C'est, (+ 4) est la fonction \x -> x + 4 et (4 +) est la fonction \y -> 4 + y. Dans le cas de l'addition, ce sont des fonctions égales, mais ce n'est pas vraiment important en ce moment.

Maintenant, nous allons essayer la même astuce sur $:

Prelude> :t ($ [1,2,3,4]) 
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b 

Maintenant surprise, à ce jour, nous avons eu \f -> f $ [1,2,3,4]. Nous pouvons également écrire

Prelude> :t (length $) 
(length $) :: [a] -> Int 

pour obtenir la fonction \l -> length $ l. Mais qu'en est-il de:

Prelude> :t ($ length) 
($ length) :: (([a] -> Int) -> b) -> b 

Ceci est étrange, mais c'est logique! Nous avons obtenu \f -> f $ length, c'est-à-dire, Une fonctionnelle qui attend d'obtenir une fonction f de type ([a] -> Int) -> b) qui sera appliqué à length. Il y a une quatrième possibilité:

Prelude> :t ([1,2,3,4] $) 

<interactive>:1:2: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: ([1, 2, 3, 4] $) 

Tout est comme il devrait être parce que [1,2,3,4] n'est pas une fonction. Que faire si nous écrivons $ entre parenthèses? Ensuite, sa signification particulière comme un opérateur infixe disparaît:

Prelude> :t (($) length) 
(($) length) :: [a] -> Int 

Prelude> :t (($) [1,2,3,4]) 
<interactive>:1:6: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: (($) [1, 2, 3, 4]) 

Prelude> :t (length ($)) 
<interactive>:1:9: 
    Couldn't match expected type `[a0]' 
       with actual type `(a1 -> b0) -> a1 -> b0' 
    In the first argument of `length', namely `($)' 
    In the expression: (length ($)) 

Prelude> :t ([1,2,3,4] ($)) 
<interactive>:1:2: 
    The function `[1, 2, 3, 4]' is applied to one argument, 
    but its type `[t0]' has none 
    In the expression: ([1, 2, 3, 4] ($)) 

Donc, pour répondre à votre question: $ [1,2,3,4] est analysé comme \f -> f $ [1,2,3,4] il est parfaitement logique de l'appliquer à length. Cependant ($) [1, 2, 3, 4] n'a pas beaucoup de sens car ($) n'est pas vu comme un opérateur infixe.

Par ailleurs, $ ne « pas faire quoi que ce soit », pour ainsi dire. Il est principalement utilisé pour une entrée plus lisible car il a une faible priorité et donc nous pouvons écrire f $ g $ h $ x au lieu de f (g (h x)).

+1

'-' peut avoir été un mauvais choix d'exemple, car c'est la seule et unique exception où' (op arg) 'ne représente * pas * une fonction. –

+1

De même, '((-) 4)' et '(4 -)' ont la même fonction, '(\ x -> 4 - x)'. –

+0

Cela signifie-t-il que (-) reste associé, ((-) 4) et (4 -) signifient (\ x -> 4 - x), alors que ($) est associé à droite, ($ func) et ($ arg) signifie (\ x -> bar $ a) où un moyen func ou arg? – Znatz

10

Votre question est vraiment ce qu'on appelle les sections de l'opérateur. Avec n'importe quel opérateur dans Haskell (je vais utiliser + comme exemple), vous pouvez écrire quelque chose comme (+ arg) ou (arg +). Ce sont juste une syntaxe abrégée pour les fonctions anonymes (\x -> x + arg) et (\x -> arg + x), respectivement.

Ainsi, la syntaxe ($ [1..5]) signifie simplement (\x -> x $ [1..5]) qui est le même que (\x -> x [1..5]) (ie. Une fonction qui passe [1..5] à la fonction passée comme argument).

+0

Ceci (\ x -> x $ [1..5]) efface vraiment ma confusion! – Znatz

Questions connexes