所以我想在这个函数中输入两个参数,一个列表和我要打印的项目的位置。
listNumber [1,2,3,4,5,6] 2
>> 3
我已经通过这样做尝试了这个问题
numberList :: (List a) => a -> a -> a
numberList a b = [x | x <- a !! n, n <- b]
我不知道我的错误在哪里。
所以我想在这个函数中输入两个参数,一个列表和我要打印的项目的位置。
listNumber [1,2,3,4,5,6] 2
>> 3
我已经通过这样做尝试了这个问题
numberList :: (List a) => a -> a -> a
numberList a b = [x | x <- a !! n, n <- b]
我不知道我的错误在哪里。
我认为这是一种有趣的方式。
如果我们暂时忽略类型签名并查看函数:
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
所以我想在这个函数中输入两个参数,一个列表和我要打印的项目的位置。
>>> 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 -> a
在http://haskell.org/hoogle中输入类型签名。事实证明,您正在尝试实施!!
.