我刚刚开始学习Haskell,我似乎找不到有条件地创建列表的好方法。
基本上,我想要的是使用if/else
进行列表理解,但没有else
部分。我确信这是可能的,我想我只是在google搜索任务中使用错误的关键字。
Python中我想要Haskellize的一个非常愚蠢的例子:
[x for x in range(11) if x > 5]
在Haskell中,据我所知,我们不能像在Python示例中那样省略else
块。我该怎么做这样的事情?是否存在类似 nothing 之类的东西,我可以添加到列表理解中的else
- 块中,如下所示:
[if x > 5 then x else Nothing | x <- [0..10]]
我实际上遇到了Haskell中的 Nothing ,尽管我还没弄明白。它当然似乎没有做我希望的。基本上我不想在列表理解中使用else
,但如果它是必要的邪恶,我想在else
块中不插入任何内容。
我可以想到一堆黑客可以非常低效地获得类似的功能:
filter
,例如filter (>5) [0..10]
concat
中创建一个列表,例如: concat [if x > 5 then [x] else [] | x <- [0..10]]
但这些想法似乎都非常丑陋。
当然在实践中我不想创建具有这些微不足道条件的条件列表。
答案 0 :(得分:21)
使用此:
Prelude> [x | x <- [0..10], x > 5]
[6,7,8,9,10]
在Haskell列表推导中,“源”表达式和所有过滤器/ ifs都是“兄弟”,即与Python不同,它们之间没有太多的语法区别。所以
<expr1> for <source_expr> if <cond_expr>
就是Haskell中的这个:
[<expr1> | <source_expr>, <cond_expr>, ...]
(source_expr
在Python中为x in range(0, 10)
或在Haskell中为x <- [0..9]
你可以在Haskell列表理解中拥有尽可能多的“source”和“filter”表达式。
这也意味着你可以用更接近数学符号的风格写东西;考虑:
{ x : x ∈ [0, 10), x > 5 }
并且看看Haskell版本与Python版本几乎相同,后者看起来更具程序性/必要性。
这也很简单,不需要使用多个“源”表达式的其他语法/结构:
Prelude> [(x, y) | x <- [0..10], y <- [10..20], y - x < 5]
[(6,10),(7,10),(7,11),(8,10),(8,11),(8,12),(9,10),(9,11),(9,12),(9,13),(10,10),(10,11),(10,12),(10,13),(10,14)]
在Python中你必须拥有看起来像嵌套列表理解的东西,但是Haskell仍然只是坚持数学方法/符号。
答案 1 :(得分:3)
在Haskell中,Python调用if
的内容并不存在。对于&#34;如果没有其他&#34;要有意义,你需要一个什么样的概念&#34;什么都不做&#34;甚至意味着 - 通常,这个想法在函数式语言中没有意义,因为函数都是关于我保证你,因为你给我的任何论据我都会回复一个有用的答案 。你不能只是说,&#34;不,不想回报任何东西&#34; ... 除非没有结果恰好是返回类型的值。事实上,这是为列表提供的,这是首先考虑过滤的唯一原因。
更一般地说,&#34;虚无&#34;被一种特殊的monad捕获:the MonadPlus
class。事实上,最简单的实例是您已经偶然发现的Nothing
构造函数:
Prelude Control.Monad&gt; mzero ::也许Int 没有
您看到它的类型中有Maybe
,即我们明确指出它不能保证会有结果!
选择&#34;产生某种东西,或不产生&#34;在Haskell中不是if
,而是guard
。在monadic写作中,你的理解看起来如此:
yourList = do
x <- [0..11]
guard (x > 5)
return x
实际上,列表理解[ x | x <- [0..11], x>5 ]
基本上就是语法糖。
guard
有点奇怪。还有另外一种功能,你经常会看到它做了非常相似的事情(虽然方式完全不同),when
,这个功能通常用于&#34;执行 - 或 - 别&#39;叔如果&#34;用命令语言。