1

所以我想在这个函数中输入两个参数,一个列表和我要打印的项目的位置。

listNumber [1,2,3,4,5,6] 2
>> 3

我已经通过这样做尝试了这个问题

numberList :: (List a) => a -> a -> a
numberList a b = [x | x <- a !! n, n <- b]

我不知道我的错误在哪里。

4

2 回答 2

4

我认为这是一种有趣的方式。
如果我们暂时忽略类型签名并查看函数:

numberList a b = [x | x <- a !! n, n <- b]

我们看到在列表理解的第一个条件中调用了 n:

x <- a !! n 

但 n 仅在此之后定义,在第二个条件下:

n <- b

这会导致错误:不在范围内:`n'

所以首先要做的可能是切换第一个和第二个条件:

numberList a b = [x | n <- b, x <- a !! n]

现在向 GHCi 询问类型,我们得到:

Prelude> :t numberList
numberList :: [[t]] -> [Int] -> [t]

GHC 期望参数 a 是列表列表,参数 b 是整数列表。这是因为 n 是从 b 中提取的,并且列表推导中 <- 右侧的任何内容都必须是列表。由于 n 用作 !! 的参数,因此 GHC 假定 n 是一个 int 并且 b 是一个 int 列表。

现在 GHC 假设 x 也来自某种列表。所以我们知道 GHC 假设一个 !! n 是一个列表。但是,根据定义,a !! n 是列表 a 在位置 n 的元素,我们看到了为什么 GHC 假设 a 是列表的列表——因为 GHC 假设列表 a 的位置 n 的元素是从中提取 x 的列表。

这是一个工作示例:

Prelude> numberList [[1,2,3,4,5,6]] [0]
[1,2,3,4,5,6]

这里 GHC 确实向我们展示了列表 a 在位置 0 的元素,即列表 [1..6]。不幸的是,这不允许我们像我们希望的那样方便地到达列表中的位置。仍然使用列表推导式的另一种方法可能是定义一个新列表“c”,其中包含我们之后的元素(a !! n)并从这个新列表中绘制 x,如下所示:

Prelude> let numberList a b = [x | n <- b, let c = [a !! n], x <- c]
Prelude> numberList [1,2,3,4,5,6,3] [2]
[3]

不过,这似乎有点令人费解,因为我们可以简单地使用 !! 直接在位置 b 处获取 a 的元素:

Prelude> let numberList a b = a !! b
Prelude> numberList [1,2,3,4,5,6] 2
3
于 2013-03-11T03:48:02.250 回答
3

所以我想在这个函数中输入两个参数,一个列表和我要打印的项目的位置。

>>> listNumber [1,2,3,4,5,6] 2
3

好的。第一步:你有一个非常混乱的类型签名。

numberList :: (List a) => a -> a -> a

这不应该被忽视。从一个好的类型签名开始是掌握 Haskell 和类似语言的良好编程技术的基本技能。

首先,您需要一个具有两个输入的函数。

numberList :: a -> b -> c

接下来,您希望第一个输入是“列表”。我们不知道这个列表包含什么,所以我们只使用一个类型参数a。写“列表a”的方法是[a]

numberList :: [a] -> b -> c

您希望第二个输入是“位置”。这可能是一个Int.

numberList :: [a] -> Int -> c

最后,您希望结果是列表的一个元素。因此它将具有相同的类型a

numberList :: [a] -> Int -> a

我不知道你从哪里得到(List a) =>了类型签名的那一部分,但它完全是假的,除非你使用了一些你没有告诉我们的自定义库。如果你正在学习 Haskell 的大学课程,这是很有可能的。

我们有一个类型签名,知道它是否已经为我们实现可能会很方便。停止!胡歌时间。[a] -> Int -> ahttp://haskell.org/hoogle中输入类型签名。事实证明,您正在尝试实施!!.

于 2013-03-11T18:52:48.710 回答