J'apprends Haskell et je faisais un programme de base de données simple pour Yesod quand je suis tombé sur ce comportement que j'ai du mal à comprendre:
testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []
Session Yesod GHCI:
$ :t concatMap testFn [3]
concatMap testFn [3] :: Bool -> [Int]
$ (concatMap testFn [1,2,3]) True
[1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3]
D'une manière ou d'une autre, il a pu «extraire» ce deuxième «booléen» de chacune des correspondances en un seul argument curry.
La session Standard Prelude GHCI de base refuse même de compiler cette expression:
$ :t concatMap testFn [3]
error:
• Couldn't match type 'Bool -> [Int]' with '[b]'
Expected type: Int -> [b]
Actual type: Int -> Bool -> [Int]
• Probable cause: 'testFn' is applied to too few arguments
In the first argument of 'concatMap', namely 'testFn'
In the expression: concatMap testFn [3]
Il s'avère que Yesod utilise une bibliothèque mono-traversable qui a la sienne concatMap
:
$ :t concatMap
concatMap
:: (MonoFoldable mono, Monoid m) =>
(Element mono -> m) -> mono -> m
À mon niveau actuel de compréhension de Haskell, je ne pouvais pas comprendre comment les types sont distribués ici. Quelqu'un pourrait-il m'expliquer (autant pour les débutants que possible) comment cette astuce est réalisée? Quelle partie de ce qui testFn
précède est conforme au Element mono
type?