习惯于条件列表理解的方法

Mar*_*sen 10 haskell list-comprehension

我刚开始学习Haskell,我似乎找不到有条件地创建列表的好方法.

基本上,我想要的是列表理解与if/else但没有else部分.我确信这是可能的,我想我只是在google搜索任务中使用了错误的关键字.

Python中我想要Haskellize的一个非常愚蠢的例子:

[x for x in range(11) if x > 5]
Run Code Online (Sandbox Code Playgroud)

在Haskell中,据我所知,我们不能else像在Python示例中那样省略块.我该怎么做这样的事情?什么都不存在,我可以添加到else列表理解中的-block,如下所示:

[if x > 5 then x else Nothing | x <- [0..10]]
Run Code Online (Sandbox Code Playgroud)

我实际上在Haskell中遇到了Nothing,尽管我还没弄明白.它当然似乎没有做我希望的.基本上我不希望else我的列表理解,但如果它是一个必要的邪恶我想在else块中插入任何东西.

我可以想到一堆黑客可以非常低效地获得类似的功能:

  • filter 创建后的列表,例如 filter (>5) [0..10]
  • 使用列表推导创建列表列表,我可以在else块中创建一个空列表,然后是concat它们,例如concat [if x > 5 then [x] else [] | x <- [0..10]]

这些想法都显得实在难看,虽然.

在实践中,我不想创建具有这些微不足道条件的条件列表.

Eri*_*lun 22

用这个:

Prelude> [x | x <- [0..10], x > 5]
[6,7,8,9,10]
Run Code Online (Sandbox Code Playgroud)

在Haskell列表推导中,"源"表达式和所有过滤器/ ifs都是"兄弟姐妹",即它们之间没有太多的语法区别,与Python不同.所以

<expr1> for <source_expr> if <cond_expr>
Run Code Online (Sandbox Code Playgroud)

在哈斯克尔就是这样:

[<expr1> | <source_expr>, <cond_expr>, ...]
Run Code Online (Sandbox Code Playgroud)

(source_exprx in range(0, 10)在Python或x <- [0..9]在Haskell)

你可以在Haskell列表理解中拥有尽可能多的"source"和"filter"表达式.

这也意味着你可以用更接近数学符号的风格写东西; 考虑:

{ x : x ? [0, 10), x > 5 }
Run Code Online (Sandbox Code Playgroud)

并且看看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)]
Run Code Online (Sandbox Code Playgroud)

在Python中你必须拥有看起来像嵌套列表理解的东西,但是Haskell仍然只是坚持数学方法/符号.


lef*_*out 5

Python 调用的东西if在 Haskell 中并不存在。为了使“如果没有其他”完全有意义,您需要了解“什么都不做”甚至意味着 \xe2\x80\x93 通常的概念,这个想法在函数式语言中没有意义,因为函数都是关于I向你保证,对于你给我的任何论点,我都会返回一个有用的答案。你不能只是说,“不,不想返回任何东西”......除非没有结果恰好是返回类型的值。事实上,这是针对列表给出的,这是首先考虑过滤有用的唯一原因。

\n\n

更一般地说,“虚无”是由一种特定类型的单子捕获的MonadPlus。事实上,最简单的实例是Nothing您已经偶然发现的构造函数:

\n\n
\n

Prelude Control.Monad> mzero :: Maybe Int
\n Nothing

\n
\n\n

你看它有Maybe它的类型,即我们明确表示不保证会有结果

\n\n

if在 Haskell 中不调用“产生某些东西,或不产生某些东西”之间的选择,而是调用guard. 在单子写作中,你的理解是这样的:

\n\n
yourList = do\n   x <- [0..11]\n   guard (x > 5)\n   return x\n
Run Code Online (Sandbox Code Playgroud)\n\n

事实上,列表理解[ x | x <- [0..11], x>5 ]基本上就是语法糖。

\n\n

guard如果你不了解 monad,那就有点奇怪了。您还会经常看到另一个函数,它执行非常相似的操作(尽管方式完全不同),when该函数通常用于“执行或不执行”t\xe2\x80\x93if “在命令式语言中。

\n

  • 正如我所说,“guard”确实有点令人困惑并且不经常使用。实际上,惯用的方法是使用“过滤器”(或类似的东西)或列表推导式。命令式“if”不是由“guard”建模的,而是由“when”建模的,所以也许最好阅读一下。- 至于 [_guards_](http://learnyouahaskell.com/syntax-in-functions#guards-guards):这些又是不同的东西,本质上只是一种更好的方式来编写长的“if-then-elseif-else”。 ..`。它们不是用“guard”实现的,与 monad 无关。 (2认同)