在Haskell中实现List#flatten

时间:2015-01-05 05:15:30

标签: scala haskell

Scala提供从List#flattenList[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函数?

3 个答案:

答案 0 :(得分:10)

您的flattencatMaybes (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已经存在flattenData.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的更多信息。