Estou aprendendo Haskell e estava fazendo um programa simples de semente de banco de dados para Yesod quando me deparei com esse comportamento que acho difícil de entender:
testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []
Sessão 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]
De alguma forma, ele foi capaz de "extrair" o segundo "Bool" de cada um dos mapeamentos em um único argumento.
A sessão Prelude GHCI de base padrão se recusa a compilar essa expressão:
$ :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]
Acontece que o Yesod usa uma biblioteca mono-atravessável que possui sua própria concatMap
:
$ :t concatMap
concatMap
:: (MonoFoldable mono, Monoid m) =>
(Element mono -> m) -> mono -> m
No meu nível atual de entendimento de Haskell, não conseguia descobrir como os tipos são distribuídos aqui. Alguém poderia me explicar (o mais orientado para iniciantes possível) como esse truque é feito? Que parte testFn
acima está em conformidade com o Element mono
tipo?