Comment puis-je comprendre": t ((==) )" à Haskell?
Je suis nouveau à Haskell, ici avoir des ennuis avec <*>
:
((==) <*>) :: Eq a => (a -> a) -> a -> Bool
Comment puis-je comprendre cela et comment cela peut être déduit?
1 réponses
Avertissement: Ce n'est pas du code Haskell idiomatique.
La première chose qui prime est la "section opérateur" de <*>
. Lorsque vous voyez un opérateur appliqué uniquement à un argument appelé section. Voici un exemple d'une section d'opérateur plus commune:
(1 +) :: Int -> Int
C'est une fonction qui applique partiellement +
à 1, laissant place à un dernier argument. C'est équivalent à:
\x -> 1 + x
Donc, dans votre exemple de code, le <*>
est partiellement appliqué à (==)
, donc nous allons étendre cela à:
((==) <*>)
= \g -> (==) <*> g
Ensuite, vous devez comprendre ce que fait le <*>
. C'est un membre de la classe de type Applicative
:
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Cela signifie que <*>
est surchargé pour fonctionner sur tout type qui implémente Applicative
. Une instance du type Applicative
est ((->) r)
:
instance Applicative ((->) r) where
pure :: a -> ((->) r) a
(<*>) :: (->) r (a -> b) -> (->) r a -> (->) r b
Les parenthèses autour du (->)
signifient qu'il est utilisé sous forme de préfixe (ce qui est nécessaire pour des raisons syntaxiques lors de la définition d'instances de classe comme celle-ci). Si vous développez pour infix forme que vous obtenez:
instance Applicative ((->) r) where
pure :: a -> r -> a
(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
Dans votre exemple spécifique, le premier argument de <*>
est l'opérateur (==)
, qui a le type suivant:
(==) :: Eq e => e -> e -> Bool
Par conséquent, si nous le passons au (<*>)
le compilateur peut en déduire plus sur les types de r
, a
, et b
dans la signature pour (<*>)
:
(<*>) :: (r -> a -> b ) -> (r -> a) -> (r -> b)
(==) :: Eq e => e -> e -> Bool
| | |
| | +-> `b` must be `Bool`
| |
| +------> `a` must be `e`
|
+-----------> `r` must also be `e`
Ainsi, lorsque nous fournissons (==)
comme premier argument de (<*>)
nous obtenons ce type déduit:
((==) <*>) :: Eq e => (e -> e) -> (e -> Bool)
Vous pouvez laisser les parenthèses droites parce que (->)
est droit-associatif, et changez e
en a
pour donner la signature finale que vous avez obtenue:
((==) <*>) :: Eq a => (a -> a) -> a -> Bool
, Mais qu'est-ce que cela fait? Pour comprendre que nous devons voir comment (<*>)
est défini pour l'instance Applicative
de ((->) r)
:
(f <*> g) r = f r (g r)
Si nous remplaçons f
par (==)
nous obtenons:
((==) <*> g) r = (==) r (g r)
Lorsque nous entourons (==)
de parenthèses, cela signifie que nous l'utilisons en notation de préfixe. Cela signifie que si nous supprimons les parenthèses et les changeons en notation infixe nous obtenir:
((==) <*> g) r = r == (g r)
, Ceci est équivalent à:
((==) <*>) = \g r -> r == g r
Cela signifie Donc que votre fonction prend deux paramètres: g
et r
, puis voit si r
est égal à g r
.