2

我必须制作一个 2D 列表[[Int]][Int]在 Haskell的一维列表中。

该函数应采用 args "r" Int 指示行数和一维列表,应将其切成长度为 "r" 的行。

如果列表的长度比 r*r 长,则应删除列表的其余部分。但是如果列表的长度比 r*r 短,那么缺失的元素应该作为 0 插入到列表中。

示例 1:

输入:r = 2

列表 = [1,2,3,4,5,6]

输出:[[1,2],[3,4]]

示例 2:

输入:r = 3

列表 = [1,2,3,4,5,6]

输出:[[1,2,3],[4,5,6],[0,0,0]]

所以我的方法是通过以下功能:

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。返回一个普通列表。

有人可以帮我吗?

4

3 回答 3

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)

解释:

  1. 将列表扩展无限个零,这样我们就不必再担心填充了。
  2. 创建一个chunks函数,将任何列表拆分为给定长度的块。
  3. 应用于chunks填充列表。
  4. 根据需要获取尽可能多的行。
于 2013-05-07T16:05:57.687 回答
1

我可以解释这两个编译错误,我有一个问题要问你。我将以相反的顺序处理错误。

14:54 出错

首先,我将解释如何将参数应用于 Haskell 中的函数。

该函数make2DList具有类型Int -> [Int] -> [[Int]],它等价于Int -> ( [Int] -> [[Int]] )。这意味着,如果给定一个参数r(必须是 type Int),它会返回一个 type 的函数[Int] -> [[Int]]。这个返回的函数,如果给定一个参数myList(它必须是 type [Int])返回一个 type 的列表[[Int]]

这意味着代码make2DList r myList等效于(make2DList r) myList. 在任何情况下,它都必须返回一个类型的值[[Int]],即Ints 的列表列表。

但是你说过,如果它myList是空的,它应该返回 just make2DList。不幸make2DList的是,它是一个类型的函数,Int -> [Int] -> [[Int]]而不是一个类型列表的列表[[Int]],因此编译器错误消息

    Couldn't match expected type `[[Int]]'
                with actual type `Int -> [Int] -> [[Int]]'

解决方法是为此调用提供一些参数make2DList。但不要提供空列表作为第二个参数,否则您将创建一个无限循环。可能您实际上想要做的是返回一个空列表列表,其编写方式与任何内容的空列表相同:[]

编辑:我也许还应该解释一下if……在 Haskell 中then是如何工作的。else这一点不像命令式语言中的 if/then/else,实际上就像三元运算符。那是,

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(不带参数),它当然是一个函数,而不是应有的列表列表。

6:63 出错

的类型由:给出(:) :: a -> [a] -> [a]。这意味着如果左侧的任何内容:has 类型a(对于某些a),那么右侧的任何内容都应该具有 type [a]

也就是说,出现在左侧的:将成为结果列表中的第一个元素,而出现在右侧的:将成为列表的其余部分,这意味着列表其余部分的类型必须是第一个元素的类型列表。

您的第一个元素是myList,它具有 type [Int],而您尝试用于列表的其余部分的是(zeroList r myList),它也具有 type [Int],因此只能作为单个元素使用。

可能的修复(可以编译,但可能正确也可能不正确)可能包括:

  • 括在方括号zeroList r myList中,因此:

    myList:[zeroList r myList]
    

    它总是会创建一个包含两个元素的列表,每个元素都是Ints的列表

  • 连接两个列表,因此:

    myList ++ (zeroList r myList)
    

    但这会产生错误的返回类型,因此您必须将结果放在另一个列表中。以下将编译,但几乎可以肯定不是您想要的:

    [myList ++ (zeroList r myList)]
    

r可能也想成为类似的r - (length myList)东西。

问题

我无法猜测您的功能应该如何工作。这两个功能分别是什么processListmake2DList应该做什么?我看到它们都具有相同的类型,那么有什么区别?

于 2013-05-07T16:17:39.980 回答
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     "
于 2017-02-15T08:40:44.973 回答