我必须制作一个2D列表[[Int]]
。在Haskell中的一维列表[Int]
中。
该函数应采用args“r”Int表示行数和1D列表,应将其切成长度为“r”的行。
如果列表的长度超过r * r,则应删除列表的其余部分。 Howerver 如果列表的长度小于r * r,那么缺失的元素应该在列表中插入为0。
示例1:
输入: r = 2
list = [1,2,3,4,5,6]
输出:[[1,2],[3,4]]
示例2:
输入: r = 3
list = [1,2,3,4,5,6]
输出:[[1,2,3],[4,5,6],[0,0,0]]
所以我的方法是关于thre函数,如下所示:
zeroList :: Int -> [Int] -> [Int]
zeroList r myList = (take (r*r-(length myList)) (0 : zeroList r myList))
processList :: Int -> [Int] -> [[Int]]
processList r myList = (if (length myList < r*r)
then (myList:(zeroList r myList))
else if (length (myList > r*r))
then (reverse (drop r (reverse myList)))
else
myList)
make2DList :: Int -> [Int] -> [[Int]]
make2DList r myList = (if myList == []
then make2DList
else ( ( take r (processList r myList) ):( make2DList r ( drop r (processList r myList) ) )))
zeroList函数正常工作,但其他两个函数不起作用。我编写了一些错误消息:
D:\haskell\task1.hs:6:63:
Couldn't match expected type `[Int]' with actual type `Int'
Expected type: [[Int]]
Actual type: [Int]
In the return type of a call of `zeroList'
In the second argument of `(:)', namely `(zeroList r myList)'
D:\haskell\task1.hs:14:54:
Couldn't match expected type `[[Int]]'
with actual type `Int -> [Int] -> [[Int]]'
In the expression: make2DList
In the expression:
(if myList == [] then
make2DList
else
((take r myList) : (make2DList r (drop r myList))))
In an equation for `make2DList':
make2DList r myList
= (if myList == [] then
make2DList
else
((take r myList) : (make2DList r (drop r myList))))
Failed, modules loaded: none.
Prelude>
我无法理解,为什么它虽然zeroList r myList
不起作用。返回一个普通的列表。
有人可以帮我吗?
答案 0 :(得分:5)
我不得不承认我不理解你是怎么做的。所有这些if then else
都非常缺乏。 :-)另外,由于Haskell的惰性评估和无限列表,没有必要事先计算所需的零的确切数量。
草稿如何改为:
make2DList r l = take r . chunks r $ l ++ zeroes
where
zeroes = [0,0..]
chunks r xs = take r xs : chunks r (drop r xs)
说明:
chunks
函数,将任何列表拆分为给定长度的块。chunks
应用于填充列表。答案 1 :(得分:1)
我可以解释两个编译错误,我有一个问题要问你。我会以相反的顺序接受错误。
首先,我将解释如何将参数应用于Haskell中的函数。
函数make2DList
的类型为Int -> [Int] -> [[Int]]
,相当于Int -> ( [Int] -> [[Int]] )
。这意味着,如果给定一个参数r
(必须是Int
类型),它将返回类型为[Int] -> [[Int]]
的函数。如果给出参数myList
(必须是[Int]
类型),则返回此函数将返回类型[[Int]]
的列表。
这意味着代码make2DList r myList
等同于(make2DList r) myList
。在任何情况下,它都必须返回[[Int]]
类型的值,即Int
s的列表列表。
但是你已经说过,如果myList
为空,它应该只返回make2DList
。不幸的是make2DList
是类型Int -> [Int] -> [[Int]]
的函数,而不是类型[[Int]]
的列表列表,因此编译器错误消息
Couldn't match expected type `[[Int]]'
with actual type `Int -> [Int] -> [[Int]]'
修复是为make2DList
的此调用提供一些参数。但是不要提供空列表作为第二个参数,否则您将创建一个无限循环。你真正想要做的就是返回一个空的列表列表,其编写方式与任何空列表相同:[]
编辑:我或许也应该解释if
... then
... else
如何在Haskell中运行。这完全不像命令式语言中的if / then / else,实际上就像ternary operator一样。也就是说,
if a then b else c
据我所知,在Haskell中的与
完全相同a ? b : c
用另一种语言。
因此,为了使整个表达式(if a then b else c)
具有正确的类型,b
和c
必须属于正确的类型(并且a
必须是布尔值,当然)。在您的情况下,整个if / then / else表达式应该是[[Int]]
类型,但您的b
是表达式make2DList
(没有参数),这当然是一个函数而不是列表应该是。
:
的类型由(:) :: a -> [a] -> [a]
给出。这意味着,如果:
左侧的内容类型为a
(某些 a ),则右侧的任何内容都应为[a]
类型
也就是说,:
左侧出现的任何内容都将成为结果列表中的第一个元素,:
右侧的任何内容都将成为其余部分list ,这意味着列表其余部分的类型必须是第一个元素所属类型的列表。
您的第一个元素是myList
,其类型为[Int]
,您尝试用于列表其余部分的是(zeroList r myList)
,其类型为{{1}因此,它只是一个单独的元素。
可能的修复(可编译,但可能或可能不正确)可能包括:
将[Int]
括在方括号中,因此:
zeroList r myList
总是会创建一个包含两个元素的列表,每个元素都是myList:[zeroList r myList]
的列表
连接两个列表,因此:
Int
但这会产生错误的返回类型,因此您必须将结果放在另一个列表中。以下是编译,但几乎肯定不是你想要的:
myList ++ (zeroList r myList)
[myList ++ (zeroList r myList)]
可能希望成为r
之类的东西。
我无法猜测你的功能应该如何工作。这两个函数r - (length myList)
和processList
应该做什么?我看到它们都有相同的类型,那有什么区别?
答案 2 :(得分:0)
import Data.List (replicate)
takeElse :: Int -> a -> [a] -> [a]
takeElse 0 _ _ = []
takeElse n alt [] = replicate n alt
takeElse n alt (x : xs) = x : takeElse (n - 1) alt xs
exotic :: Int -> a -> [a] -> [[a]]
exotic dum alt lst = exot dim lst
where
exot 0 _ = []
exot n xs = takeElse dim alt xs : exot (n - 1) (drop dim xs)
这样
exotic 3 0 [1,2,3,4] == [[1,2,3],[4,0,0],[0,0,0]]
exotic 1 ' ' "Hello" == ["H"]
exotic 4 ' ' "Hello" == ["Hell","o "," "," "]
takeElse 10 ' ' "Hello" == "Hello "