【问题标题】:List Comprehension: Even numbers from 0 to x列表理解:从 0 到 x 的偶数
【发布时间】:2020-01-16 22:46:23
【问题描述】:

我目前正在学习 Haskell,我必须说,我过得很糟糕。

我的任务是创建一个函数 evens,它接受一个值 x,并返回从 0x 的所有偶数值的列表。

例如:

>  evens 10

> [2,4,6,8,10]

我一直在尝试使用列表推导来修改一些示例函数以实现我的目标,但是我只是被错误所困扰,更糟糕的是,即使我尝试了这么多事情,一切都是一个令人困惑的模糊。

我最后一次尝试如下:

evens :: int -> [int]
evens n = [x | x <- [0..n], filter even x]

它产生了错误:

ex1.hs:9:29: 错误:

• 无法将预期类型“Bool”与实际类型“[Integer]”匹配

• 在表达式中:filter even x

在列表理解中:filter even x

在表达式中:[x | x &lt;- [0 .. n], filter even x]

我确实看到它期待一个布尔值,但坦率地说,我不明白在哪里或为什么。

任何帮助将不胜感激。我从来没有任何函数式编程语言的经验,而且我很难弄清楚我的思想错误。我觉得我把这个简单的问题想多了,到了难以置信的地步。

【问题讨论】:

  • 列表推导中的布尔表达式已被视为过滤器。你不需要说filter even x,你只需说even x。此外,语言区分大小写,请确保在类型签名中使用 Int 而不是 int
  • 很抱歉听到这个消息。 List comprehensions are fun。 :)
  • 不值得写一个答案,但没有人告诉你最好的解决方案:evens n = [0,2..n]

标签: list function haskell filter list-comprehension


【解决方案1】:

只需从该代码中删除单词filter

预期的Booleaneven x。当此值为True 时,x 将包含在输出列表中。

filter 是一个 list 创建函数,但列表推导本身已经在创建一个列表。

其实filter p可以这样编码

filter p xs = [x | x <- xs, p x]

所以在内部使用filter 是相当多余的。


关于该错误消息。你说

我确实看到它期待一个布尔值,但坦率地说,我不明白在哪里或为什么。

但是错误信息告诉我们在哪里

ex1.hs:9:29: 错误:

• 无法将预期类型“Bool”与实际类型“[Integer]”匹配

• 在表达式中:filter even x

这里就是。这是最直接的罪魁祸首:表达式filter even x它的实际类型 [Integer] 与预期类型 Bool 不匹配。

在列表理解中:filter even x

该表达式在我们的列表理解中以 "stmt" 语句的形式出现在 in 中,

在表达式中:[x | x &lt;- [0 .. n], filter even x]

就是上面的完整表达式。所以我们只需要从里到外阅读这些消息,以找到通往(直接)错误位置的路。


因此,从列表理解的上下文 [ r | x &lt;- xs, q] 来看,q 应该具有 Bool 类型。

q = filter even x 本身具有[Integer] 类型,即整数列表。

为什么?因为(与此上下文相关的简化的非多态类型)

  filter      :: (Integer -> Bool) -> [Integer] -> [Integer]
         even :: (Integer -> Bool)
  -----------------------------------------------------------
  filter even ::                      [Integer] -> [Integer]
              xs                   :: [Integer]
  -----------------------------------------------------------
  filter even xs                                :: [Integer]

(将::读作“有类型”);而

  even   :: (Integer -> Bool)
       x ::  Integer
  ---------------------------
  even x             :: Bool

如果你想知道为什么它是Integer,即使你写了int,简短的回答是,int 是一个类型变量,就像a 或@ 987654348@ 或 t 或 ... 。它不是一个类型,比如Int。所以你会得到默认值,这里是Integer

【讨论】:

  • 我认为这里还有更多事情要做。您使用了xs :: [Integer],但 OP 使用了x :: Int。事实上:t filter even (1::Int) 抱怨说:“不能将[a]Int 匹配,而:t filter even (1::_) 报告1 的类型为[a]。新手可能会很困惑,数字1 被Haskell 接受作为一个列表([a] 类型)。也许应该在一个单独的问题中讨论这个主题,但我想为未来的读者指出这一点。
  • @MichaWiedenmann 呃,我想我现在明白你的评论了。您可能在 OP 的代码中引用了 filter even x 中的 x,从上下文中该类型称为 x :: Integer(或 Int,等等);但是当我显示类型推导时,我推导了表达式 filter even xs"in its own" 的类型,即仅从 filtereven 的类型——以遵循错误消息。 GHC 可以选择您的方法,专注于 x 而不是 filter even x,然后说“由 LC x 已知为 Int,但 filter even 预计 [a] " ....
  • 是的。 (奇怪的是,在evens :: a -&gt; [a]; evens n = [x | x &lt;- "", filter even x] 中,编译器给出了第二个警告([Integer]Char 不匹配),但它不在 `evens :: a -> [a]; evens n = [x | x
【解决方案2】:

另一种但也是正确的表述是,

Prelude> filter (\x -> even x) [1..10]
[2,4,6,8,10]

你也可以把 lambda 函数放在这里做

Prelude> filter even [1..10]
[2,4,6,8,10]

更简洁,以列表理解格式。

Prelude> [x | x <- [1..10], even x]
[2,4,6,8,10]

【讨论】:

  • \x -&gt; even x 在此上下文中等同于 even
  • 是的,这是一个等价的函数,但对于 haskell noobie,我认为当你将它表示为 lambda 时会更清楚发生了什么
  • 如果有的话,我认为这意味着表达式定义的函数与根本不存在的原始函数之间存在差异。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多