简体   繁体   English

在Haskell中实现List#flatten

[英]Implementing List#flatten in Haskell

Scala offers a List#flatten method for going from List[Option[A]] to List[A] . Scala提供了一个List#flatten方法,用于从List[Option[A]]List[A]

scala> val list = List(Some(10), None)
list: List[Option[Int]] = List(Some(10), None)

scala> list.flatten
res11: List[Int] = List(10)

I attempted to implement it in Haskell: 我试图在Haskell中实现它:

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

However I don't like the fact that g is a partial, ie non-total, function. 但是,我不喜欢g是部分(即非总体)函数的事实。

Is there a total way to write such flatten function? 是否有完整的方法来编写这样的flatten函数?

Your flatten is the same as catMaybes (link) which is defined like this: 你的flattencatMaybes (link)相同,其定义如下:

catMaybes :: [Maybe a] -> [a]
catMaybes ls = [x | Just x <- ls]

The special syntax Just x <- ls in a list comprehension means to draw an element from ls and discard it if it is not a Just . 列表理解中的特殊语法Just x <- ls意味着从ls绘制一个元素,如果它不是Just ,则丢弃它。 Otherwise assign x by pattern matching the value against Just x . 否则,分配x通过模式匹配对价值Just x

A slight modification of the code you have will do the trick: 稍微修改一下您所拥有的代码即可:

flatten :: [Maybe a] -> [a]
flatten xs = xs >>= f

f :: Maybe a -> [a]
f x = case x of Just j  -> [j]
                Nothing -> []

If we extract the value inside of the Just constructor in f , we avoid g altogether. 如果我们在f提取Just构造函数内部的值,我们完全避免g

Incidentally, f already exists as maybeToList and flatten is called catMaybes , both in Data.Maybe . 顺便说一句, f已经存在了maybeToListflatten被称为catMaybes ,无论是在Data.Maybe

One could quite easily write a simple recursive function which goes through a list and rejects all the Nothing s from the Maybe monad. 人们可以很容易地写一个简单的递归函数,它通过一个列表并拒绝所有来自Maybe monad的Nothing Here's how I'd do it as a recursive sequence: 这是我如何做一个递归序列:

flatten :: [Maybe a] -> [a]
flatten [] = []
flatten (Nothing : xs) =     flatten xs
flatten (Just x  : xs) = x : flatten xs

However, it may be clearer to write it as a fold: 但是,将它写成折叠可能更清楚:

flatten :: [Maybe a] -> [a]
flatten = foldr go []
    where go  Nothing xs =     xs
          go (Just x) xs = x : xs

Or, we could use a blindingly elegant solution thanks to @user2407038, which I'd recommend playing around with in GHCi to work out the individual functions' jobs: 或者,由于@ user2407038,我们可以使用一个非常优雅的解决方案,我建议在GHCi中使用它来计算各个功能的工作:

flatten :: [Maybe a] -> [a]
flatten = (=<<) (maybe [] (:[])

And it's faster, folded brother: 这是更快,折叠的兄弟:

flatten :: [Maybe a] -> [a]
flatten = foldr (maybe id (:))

Your solution is halfway there. 你的解决方案就在那里。 My suggestion if to rewrite your function f to use pattern matching (like my temporary go function), and enclose it in a where statement to keep relevant functions in one place. 我建议如果要重写你的函数f来使用模式匹配(比如我的临时go函数),并将它包含在where语句中以将相关函数保存在一个地方。 You've got to remember the differences in function syntax within scala and Haskell. 你必须记住scala和Haskell中函数语法的差异。

The big problem you're having is you don't know the differences I've mentioned. 你遇到的一个大问题是你不知道我提到的差异。 Your g function can use pattern matching with multiple patterns: 你的g函数可以使用模式匹配多个模式:

g :: Maybe a -> [a]
g (Just x) = [x]
g  Nothing = []

There you go: your g function is now what you call 'complete', though more accurately, it would be said to have exhaustive patterns . 你去了:你的g函数现在称为'完整',但更准确地说,它可以说是详尽的模式

You can find more about function syntax here . 您可以在此处找到有关函数语法的更多信

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM