Haskell - 从一维列表中创建一个2D列表

时间:2013-05-07 15:21:55

标签: haskell

我必须制作一个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不起作用。返回一个普通的列表。

有人可以帮我吗?

3 个答案:

答案 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)

说明:

  1. 将列表扩展为无限数量的零,这样我们就不用再担心填充了。
  2. 创建一个chunks函数,将任何列表拆分为给定长度的块。
  3. chunks应用于填充列表。
  4. 根据需要选择尽可能多的行。

答案 1 :(得分:1)

我可以解释两个编译错误,我有一个问题要问你。我会以相反的顺序接受错误。

14:54错误

首先,我将解释如何将参数应用于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)具有正确的类型,bc必须属于正确的类型(并且a必须是布尔值,当然)。在您的情况下,整个if / then / else表达式应该是[[Int]]类型,但您的b是表达式make2DList(没有参数),这当然是一个函数而不是列表应该是。

6:63错误

:的类型由(:) :: 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     "