Scala提供从List#flatten
到List[Option[A]]
的{{1}}方法。
List[A]
我试图在Haskell中实现它:
scala> val list = List(Some(10), None)
list: List[Option[Int]] = List(Some(10), None)
scala> list.flatten
res11: List[Int] = List(10)
但是,我不喜欢flatten :: [Maybe a] -> [a]
flatten xs = map g $ xs >>= f
f :: Maybe a -> [Maybe a]
f x = case x of Just _ -> [x]
Nothing -> []
-- partial function!
g :: Maybe a -> a
g (Just x) = x
是部分(即非全部)功能的事实。
是否有总方式来编写此类g
函数?
答案 0 :(得分:10)
您的flatten
与catMaybes
(link)相同,其定义如下:
catMaybes :: [Maybe a] -> [a]
catMaybes ls = [x | Just x <- ls]
列表推导中的特殊语法Just x <- ls
表示从ls
中绘制一个元素,如果它不是Just
,则将其丢弃。否则,请通过匹配x
的值的模式指定Just x
。
答案 1 :(得分:4)
稍微修改一下你所拥有的代码就可以了:
flatten :: [Maybe a] -> [a]
flatten xs = xs >>= f
f :: Maybe a -> [a]
f x = case x of Just j -> [j]
Nothing -> []
如果我们在Just
中提取f
构造函数中的值,我们会完全避免g
。
顺便提一下,f
已经存在flatten
而Data.Maybe
已{{1}} {{1}}。{/ 1}}
答案 2 :(得分:0)
可以很容易地编写一个简单的递归函数,该函数遍历列表并拒绝Maybe monad中的所有Nothing
。以下是我如何将其作为递归序列:
flatten :: [Maybe a] -> [a]
flatten [] = []
flatten (Nothing : xs) = flatten xs
flatten (Just x : xs) = x : flatten xs
然而,将它写成折叠可能更清楚:
flatten :: [Maybe a] -> [a]
flatten = foldr go []
where go Nothing xs = xs
go (Just x) xs = x : xs
或者,由于@ user2407038,我们可以使用一个令人眼花缭乱的优雅解决方案,我建议在GHCi中使用它来计算个别功能&#39;作业:
flatten :: [Maybe a] -> [a]
flatten = (=<<) (maybe [] (:[])
它更快,折叠的兄弟:
flatten :: [Maybe a] -> [a]
flatten = foldr (maybe id (:))
你的解决方案就在那里。我建议是否重写函数f
以使用模式匹配(如我的临时go
函数),并将其括在where
语句中以将相关函数保存在一个位置。您必须记住scala和Haskell中函数语法的差异。
你遇到的最大问题是你不知道我所提到的差异。您的g
函数可以使用多种模式的模式匹配:
g :: Maybe a -> [a]
g (Just x) = [x]
g Nothing = []
你去了:你的g
功能现在就是你所说的#39;完成&#39;虽然更准确地说,它会被认为具有详尽的模式。
您可以找到有关函数语法here的更多信息。