9
votes

Quelle fonction de $ réellement à Haskell?

Je sais xxx

intuitivement, il me semble que j'aiime dire, 1. $ retarder l'évaluation de la fonction à sa gauche 2. Évalue ce qui est à son droit 3. nourrit le résultat de sa gauche à sa droite.

et cela me convient parfaitement lorsque, xxx

Ce que je ne comprends pas, c'est pourquoi , xxx

juger du type de $, n'est-ce pas que son (premier) argument devrait être une fonction?


8 commentaires

Ce n'est pas sur ($) , mais sur les sections de l'opérateur.


$ Ne pas L'évaluation de la fonction est laissée. Vous pouvez le confondre avec $! , qui force une évaluation partielle de l'argument à son droit avant de l'aligner sur la fonction à sa gauche.


C'est la syntaxe de "section" au travail. haskell.org/onlinereport/hakell2010/...


Et quant à ce que c'est bon pour: Vous pouvez l'utiliser lorsque vous souhaitez appliquer une liste de fonctions à une valeur: carte ($ [1..5]) [longueur, somme, produit] .


@ dave4420 id $! x == x `SEQ` id x ne force rien, ni donc on m'a dit.


@Willness Eh bien, SEQ ou ($!) ne sont évalués que lorsque leur résultat est demandé. Depuis l'argument et le résultat de ID sont les mêmes, id $! x force l'évaluation de l'argument, x , (à une forme de tête faible) exactement lorsque le résultat, x , doit être évalué (à WHNF) . Il est donc difficile de déterminer si le ($!) a fait quelque chose là-bas. Mais dans une implémentation où a `SEQ` B évalue a avant b (qui n'est pas requis par la sémantique de SEQ ), Si vous avez l'air assez difficile, vous pouvez voir que id $! indéfini Erreurs avant ID retourne.


@Danielfischer La raison pour laquelle je m'attardais, c'est que j'étais confus par cela assez à quelques reprises en supposant que $! "force son argument". La vraie question, quand? , est laissée de côté par cette déclaration magique. Serait-il préférable de dire que $! "arrange pour que son argument soit forcé avant d'être envoyé à la fonction, lorsque le résultat de la demande de fonction est forcé"?


@Will confusion commune. Je n'ai bien sûr jamais souffert ( siffle innocemment ). La réponse est une fonction ne peut rien faire - en particulier, ne pas forcer l'évaluation de l'un de ses arguments - avant qu'elle ne soit appelée. Quand est-il appelé? Lorsque son résultat doit être évalué, non plus tôt, pas plus tard. En ce qui concerne votre édition, oui, il serait probablement préférable de dire ($!) force son deuxième argument lorsque son résultat est nécessaire pour être évalué.


3 Réponses :


6
votes

($ [1..5]) est une section. C'est un opérateur partiellement appliqué. C'est un raccourci pour (\ f -> f $ [1..5]) .

Les sections vous permettent de fournir un argument à un opérateur binaire et de produire une fonction - une fonction qui attend l'argument restant.

Jetez un coup d'œil à http://www.hakell.org/hakellwiki/section_of_an_infix_opérator < / p>


0 commentaires

10
votes

Votre question est vraiment sur ce que l'on appelle les sections de l'opérateur. Avec n'importe quel opérateur de haskell (je vais utiliser + comme exemple), vous pouvez écrire quelque chose comme (+ arg) ou (arg +) . Il s'agit juste de la syntaxe sténographie pour les fonctions anonymes (\ x -> x + arg) et (\ x -> arg + x) , respectivement.

donc, le ($ [1..5]) syntaxe signifie simplement (\ x -> x $ [1..5]) qui est le même comme (\ x -> x [1..5]) (c.-à-d. une fonction qui passe [1..5] à la fonction passée comme argument).


1 commentaires

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



16
votes

Cela a à voir avec l'analyse. Dans HASKELL, vous pouvez écrire (op-arg) code> où op code> est un opérateur d'infixe. Ce n'est pas la même chose que ((op) argone) code>. Et vous pouvez écrire (arg op) code> aussi! Par exemple: xxx pré>

c'est-à-dire, (+ 4) code> est la fonction \ x -> x + 4 code> et ( 4 +) code> est la fonction \ y -> 4 + y code>. En cas d'addition, celles-ci sont des fonctions égales, mais ce n'est pas vraiment important en ce moment. P>

Essayons maintenant le même tour sur $ code>: p>

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] ($))


7 commentaires

- peut avoir été un mauvais choix de l'exemple, car il s'agit de la seule et unique exception où (op-arg) est pas représente une fonction.


En outre, ((-) 4) et (4 -) sont la même fonction, (\ x -> 4 - x) .


Cela signifie-t-il parce que (-) est laissé associé, à la fois ((-) 4) et (4 -) moyens (\ x -> 4 - x), tandis que ($) est juste associé, à la fois ($ Func) et ($ arg) signifie (\ x -> bar $ a) où a signifie fonction de func ou argers?


Oups, laissez-moi résoudre ça. Merci, Scott.


Cela n'a rien à voir avec l'associativité. La chose qui est confuse @Znatz est que f $ Longueur est logique si f a le type correct. Ainsi, Haskell est analysant $ Longueur comme \ f -> FT $ Longueur , comme $ [1,2,3,4] est analysé comme \ f -> f $ [1,2,3,4] .


OK je vois. ($ de longueur) ((* 2).) [1..10] me donne un 20 attendu. Cependant, il est toujours très confus que ((-) 4) est analysé comme (\ x -> 4 - x) mais pas (\ x -> x - 4)


C'est parce que ((-) 4) n'est pas une section de l'opérateur du tout. C'est juste une application partielle normale de - , et il reçoit ses arguments à gauche ou droite comme toutes les autres fonctions. Comme il faut d'abord son argument gauche, vous obtenez (\ x -> 4 - x) .