Saya belajar Haskell dan sedang melakukan program DB-seed sederhana untuk Yesod ketika saya menemukan perilaku ini yang sulit saya pahami:
testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []
Sesi 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]
Entah bagaimana itu bisa "menarik" keluar itu "Bool" kedua dari masing-masing pemetaan menjadi argumen kari tunggal.
Sesi GHCI Pangkalan standar awal menolak untuk mengkompilasi ekspresi ini:
$ :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]
Ternyata Yesod menggunakan pustaka mono-traversable yang memiliki concatMap
:
$ :t concatMap
concatMap
:: (MonoFoldable mono, Monoid m) =>
(Element mono -> m) -> mono -> m
Pada tingkat pemahaman Haskell saya saat ini, saya tidak tahu bagaimana tipe didistribusikan di sini. Bisakah seseorang menjelaskan kepada saya (sebanyak mungkin pemula berorientasi) bagaimana trik ini dilakukan? Bagian mana di testFn
atas yang sesuai untuk diketik Element mono
?