我正在研究Blow Your Mind
中的Haskell习语-- split at whitespace
-- "hello world" -> ["hello","world"]
unfoldr (\b -> fmap (const . (second $ drop 1) . break (==' ') $ b) . listToMaybe $ b)
据我所知,展开者应该是:
unfoldr :: (b -> Maybe (a,b)) -> b -> [a]
unfoldr f b =
case f b of
Just (a, new_b) -> a : unfoldr f new_b
Nothing -> []
所以f b必须在最后输出Nothing,对吧?
所以我试着理解f部分fmap (const . (second $ drop 1) . break (==' ') $ b) . listToMaybe $ b)
。
我明白了第二个,下降,休息,listToMaybe。但我无法弄清楚为什么组合这样的函数可以输出Nothing。
Const
始终忽略第二个参数。那么为什么fmap (const . (second $ drop1) . break (==' ') $ b) . listToMaybe $ b
最终会输出Nothing?
答案 0 :(得分:3)
(const . (second $ drop 1) . break (==' '))
的类型为[Char] -> b -> ([Char], [Char])
这个复杂的函数只需要一个字符串(例如"one two three"
)和任何参数,然后返回("one", "two three")
。
因此,(const . (second $ drop 1) . break (==' ')) $ "one two three"
接受任何参数并返回("one", "two three")
。
fmap (const . (second $ drop 1) . break (==' ') $ b) . listToMaybe $ b
与
相同 fmap (const . (second $ drop 1) . break (==' ') $ b) $ listToMaybe b
e.g。该函数为fmapped
到Maybe
值,但fmap
实例的Maybe
定义为:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
这意味着如果fmap
中的Nothing
为a
,则fmap f a
会返回Nothing
。
listToMaybe
会返回Just
列表的第一个元素,如果列表为空则返回Nothing
。这就是为什么
fmap (const . (second $ drop 1) . break (==' ') $ b) $ listToMaybe b
Nothing
为空列表时,将返回b
。
答案 1 :(得分:2)
代码以令人困惑的方式编写。 fmap (const xyz)
基本上滥用Maybe a
作为布尔切换:如果是Just _ᴡʜᴀᴛᴇᴠᴇʀ
,则结果为Just xyz
,而简单地传递Nothing
。如果列表为空,这样的任何内容都不会直接来自listToMaybe
,这就是这个组合可以产生Nothing
的方式。
写这一切的首选方式是
unfoldr (\b -> listToMaybe b *> Just (second (drop 1) (break (==' ') b)))
或确实使用旧的旧do
符号
unfoldr $ \b -> do
listToMaybe b
return . second (drop 1) $ break (==' ') b
但实际上,明确的模式匹配会更加清晰:
{-# LANGUAGE LambdaCase #-}
unfoldr $ \case
[] -> Nothing
b -> Just . second (drop 1) $ break (==' ') b