在 Haskell 中为列表 monad 定义 bind without join
Define bind without join for the list monad in Haskell
我理解 >>=
的定义 join
xs >>= f = join (fmap f xs)
这也告诉我们 fmap + join
产生 >>=
我想知道对于 List
monad 是否可以在没有 join
的情况下定义,就像我们为 Maybe
:
所做的那样
>>= m f = case m of
Nothing -> Nothing
Just x -> f x
当然可以。 GHC/Base.hs
中的实际定义是根据等效列表理解:
instance Monad [] where
xs >>= f = [y | x <- xs, y <- f x]
或者,您可以尝试使用以下方法从头开始计算类型:
(>>=) :: [a] -> (a -> [b]) -> [b]
我们需要处理两种情况:
[] >>= f = ???
(x:xs) >>= f = ???
第一个很简单。我们没有 a
类型的元素,因此我们无法应用 f
。我们唯一能做的就是return一个空列表:
[] >>= f = []
对于第二个,x
是一个 a
类型的值,所以我们可以应用 f
给我们一个 f x
类型的值 [b]
.这是我们列表的开头,我们可以将它与递归调用生成的列表的其余部分连接起来:
(x:xs) >>= f = f x ++ (xs >>= f)
我理解 >>=
的定义 join
xs >>= f = join (fmap f xs)
这也告诉我们 fmap + join
产生 >>=
我想知道对于 List
monad 是否可以在没有 join
的情况下定义,就像我们为 Maybe
:
>>= m f = case m of
Nothing -> Nothing
Just x -> f x
当然可以。 GHC/Base.hs
中的实际定义是根据等效列表理解:
instance Monad [] where
xs >>= f = [y | x <- xs, y <- f x]
或者,您可以尝试使用以下方法从头开始计算类型:
(>>=) :: [a] -> (a -> [b]) -> [b]
我们需要处理两种情况:
[] >>= f = ???
(x:xs) >>= f = ???
第一个很简单。我们没有 a
类型的元素,因此我们无法应用 f
。我们唯一能做的就是return一个空列表:
[] >>= f = []
对于第二个,x
是一个 a
类型的值,所以我们可以应用 f
给我们一个 f x
类型的值 [b]
.这是我们列表的开头,我们可以将它与递归调用生成的列表的其余部分连接起来:
(x:xs) >>= f = f x ++ (xs >>= f)