以下是它脱糖和运作的方式。你是对的,这是:
do
a <- [1, 2, 3]
b <- [4, 5, 6]
return $ a * 10 + b
对此进行脱糖:
[1, 2, 3] >>= \a ->
[4, 5, 6] >>= \b ->
return $ b * 10 + a
反过来又使用 的列表实例,我们可以内联其和(或)Monad
的定义:>>=
return
pure
concatMap
(\a -> concatMap
(\b -> [b * 10 + a])
[4, 5, 6])
[1, 2, 3]
我们可以分解concatMap
成concat
and map
:
concat
(map
(\a -> concat
(map
(\b -> [b * 10 + a])
[4, 5, 6]))
[1, 2, 3])
现在我们可以减少它,我认为这就是你遇到困难的地方:减少是从外到内发生的,在这种情况下不会产生部分应用的函数;相反,它捕获 a
内部 lambda 的闭包(\b -> …)
。(\a -> …)
首先,我们映射[1, 2, 3]
:
concat
[ (\a -> concat
(map
(\b -> [b * 10 + a])
[4, 5, 6])) 1
, (\a -> concat
(map
(\b -> [b * 10 + a])
[4, 5, 6])) 2
, (\a -> concat
(map
(\b -> [b * 10 + a])
[4, 5, 6])) 3
]
==
concat
[ let a = 1
in concat
(map
(\b -> [b * 10 + a])
[4, 5, 6])
, let a = 2
in concat
(map
(\b -> [b * 10 + a])
[4, 5, 6])
, let a = 3
in concat
(map
(\b -> [b * 10 + a])
[4, 5, 6])
]
然后我们可以减少内部map
s:
concat
[ let a = 1
in concat
[ (\b -> [b * 10 + a]) 4
, (\b -> [b * 10 + a]) 5
, (\b -> [b * 10 + a]) 6
]
, let a = 2
in concat
[ (\b -> [b * 10 + a]) 4
, (\b -> [b * 10 + a]) 5
, (\b -> [b * 10 + a]) 6
]
, let a = 3
in concat
[ (\b -> [b * 10 + a]) 4
, (\b -> [b * 10 + a]) 5
, (\b -> [b * 10 + a]) 6
]
]
==
concat
[ let a = 1
in concat
[ let b = 4 in [b * 10 + a]
, let b = 5 in [b * 10 + a]
, let b = 6 in [b * 10 + a]
]
, let a = 2
in concat
[ let b = 4 in [b * 10 + a]
, let b = 5 in [b * 10 + a]
, let b = 6 in [b * 10 + a]
]
, let a = 3
in concat
[ let b = 4 in [b * 10 + a]
, let b = 5 in [b * 10 + a]
, let b = 6 in [b * 10 + a]
]
]
然后我们可以通过用它们的值替换变量来简化:
concat
[ concat
[ [4 * 10 + 1]
, [5 * 10 + 1]
, [6 * 10 + 1]
]
, concat
[ [4 * 10 + 2]
, [5 * 10 + 2]
, [6 * 10 + 2]
]
, concat
[ [4 * 10 + 3]
, [5 * 10 + 3]
, [6 * 10 + 3]
]
]
并减少对concat
:
concat
[ [ 4 * 10 + 1
, 5 * 10 + 1
, 6 * 10 + 1
]
, [ 4 * 10 + 2
, 5 * 10 + 2
, 6 * 10 + 2
]
, [ 4 * 10 + 3
, 5 * 10 + 3
, 6 * 10 + 3
]
]
==
[ 4 * 10 + 1
, 5 * 10 + 1
, 6 * 10 + 1
, 4 * 10 + 2
, 5 * 10 + 2
, 6 * 10 + 2
, 4 * 10 + 3
, 5 * 10 + 3
, 6 * 10 + 3
]
当然还有个别的表达方式:
[ 41, 51, 61
, 42, 52, 62
, 43, 53, 63
]
A case where you will see a list of partially applied functions is when using the Applicative
instance of lists, for example, the equivalent to your code:
(\a b -> b * 10 + a) <$> [1, 2, 3] <*> [4, 5, 6]
The definition of <$>
/fmap
for lists is just map
, so we partially apply the first argument of the lambda, producing a list of type [Int -> Int]
, then (<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
, here at type [Int -> Int] -> [Int] -> [Int]
, applies each function in its left operand to each value in its right operand.