Sto imparando Haskell e stavo facendo un semplice programma seed DB per Yesod quando mi sono imbattuto in questo comportamento che trovo difficile da capire:
testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []
Sessione GHOD di Yesod:
$ :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]
In qualche modo è stato in grado di "estrarre" quel secondo "Bool" da ciascuna delle mappature in un singolo argomento al curry.
La sessione Preludio GHCI di base standard rifiuta persino di compilare questa espressione:
$ :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]
Si scopre che Yesod utilizza una libreria mono-attraversabile che ha il suo concatMap
:
$ :t concatMap
concatMap
:: (MonoFoldable mono, Monoid m) =>
(Element mono -> m) -> mono -> m
Al mio attuale livello di comprensione di Haskell, non sono riuscito a capire come vengano distribuiti i tipi qui. Qualcuno potrebbe spiegarmi (per quanto possibile orientato il principiante) come viene fatto questo trucco? Quale parte di cui testFn
sopra è conforme al Element mono
tipo?