所以我想在这个函数中添加两个参数,一个列表以及我要打印的项目的位置。
listNumber [1,2,3,4,5,6] 2
>> 3
我这样做了
numberList :: (List a) => a -> a -> a
numberList a b = [x | x <- a !! n, n <- b]
我不知道我的错误在哪里。
答案 0 :(得分:4)
我认为这是一种有趣的方式 如果我们暂时忽略类型签名并查看函数:
numberList a b = [x | x <- a !! n, n <- b]
我们看到n在list-comprehension的第一个条件中被调用:
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是int的列表。这是因为n是从b中绘制的,并且列表理解中&lt; - 右侧的任何内容都必须是列表。由于n用作!!的参数,GHC假定n是int,b是int的列表。
现在GHC假设x也来自某种列表。所以我们知道GHC假设!! n是一个清单。但是从定义来看,一个!! n是位置n的列表a的元素,我们看到为什么GHC假定a是列表列表 - 因为GHC假定列表a的元素在位置n是从中绘制x的列表。
这是一个有效的例子:
Prelude> numberList [[1,2,3,4,5,6]] [0]
[1,2,3,4,5,6]
这里GHC确实向我们展示了位置0的列表a的元素,即列表[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的元素:
Prelude> let numberList a b = a !! b
Prelude> numberList [1,2,3,4,5,6] 2
3
答案 1 :(得分: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大学课程,这很有可能。
我们有一个类型签名,可能很方便知道这是否已经为我们实现了。停止!霍格时间。在http://haskell.org/hoogle中输入类型签名[a] -> Int -> a
。事实证明,您正在尝试实施!!
。