【问题标题】:Haskell - make a 2D list out of a 1D listHaskell - 从一维列表中制作一个二维列表
【发布时间】:2013-05-07 15:21:54
【问题描述】:

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

该函数应将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 不起作用。返回一个普通的列表。

谁能帮帮我?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    我不得不承认我不明白你是如何尝试这样做的。所有这些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. 根据需要获取尽可能多的行。

    【讨论】:

    • where chunks r $ l ++ zeroes == chunks r (l ++ zeroes) — 对于 n00b 来说可能更容易阅读
    • 感谢漂亮简洁的代码和解释。它工作得很好 - 但是我不能马上理解它:-( 1. 在 wicht 库中是块?因为当我在 Prelude 中写块时,它说&lt;interactive&gt;:1:1: Not in scope: chunks'. 2. Is it written in free-point style (1. line?) how can one write it in the "normal" (btw, what is it called?) style? 3. what do $ and zeroes = [0,0 ..]`. 做吗?
    • @Beetle 952580,谢谢。是的,确实对我来说更容易,可能对每个新手来说都是如此。对于初学者来说,免点有点棘手
    • chirlu:您可以将零定义为zeroes = repeat 0
    • 我犯了一个错误。 take r . chunks r $ l ++ zeroes 实际上应该是 (take r . chunks r) (l ++ zeroes) 而没有 $
    【解决方案2】:

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

    14:54 出错

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

    函数make2DList 的类型为Int -&gt; [Int] -&gt; [[Int]],相当于Int -&gt; ( [Int] -&gt; [[Int]] )。这意味着,如果给定一个参数r(必须是Int 类型),它会返回一个[Int] -&gt; [[Int]] 类型的函数。如果给定参数myList(必须为[Int] 类型),此返回的函数将返回[[Int]] 类型的列表。

    这意味着代码make2DList r myList 等价于(make2DList r) myList。无论如何,它必须返回一个[[Int]]类型的值,即Ints的列表列表。

    但是你说过,如果myList 为空,它应该只返回make2DList。不幸的是 make2DListInt -&gt; [Int] -&gt; [[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 -&gt; [a] -&gt; [a] 给出。这意味着如果: 左侧的任何内容具有a 类型(对于某些a),那么右侧的任何内容都应具有[a] 类型。

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

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

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

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

      myList:[zeroList r myList]
      

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

    • 连接两个列表,因此:

      myList ++ (zeroList r myList)
      

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

      [myList ++ (zeroList r myList)]
      

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

    问题

    我无法猜测您的函数应该如何工作。 processListmake2DList 这两个函数分别应该做什么?我看他们都是同类型的,那有什么区别呢?

    【讨论】:

    • 我的意图是将 make2DList 创建为“超级”函数,它应该返回最终结果。在其中它应该调用 processList 函数,该函数应该检查 myList 的长度,并且根据 myList 是否比 r*r 短或长,它应该连接一些零(对于这一步,它应该调用 zeroList)或删除元素的溢出。
    • 我发现我忘了打电话给processList。在 make2DList 中。现在我更新了它。多于!无论如何它不起作用......
    【解决方案3】:
    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     "
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-18
      • 1970-01-01
      • 2010-11-17
      • 2021-08-06
      • 1970-01-01
      • 2021-12-31
      • 2023-02-19
      相关资源
      最近更新 更多