编写递归函数调整器

Write the recursive function adjuster

编写递归函数调整器。给定一个类型列表 x,一个 int 和一个 x 类型的元素,要么从 列表直到它与 int 的长度相同,或者追加到列表的末尾 直到它与 int 指定的值的长度相同。

预计:

adjuster [1..10] (-2) 2 -> *** Exception: Invalid Size
adjuster [1..10] 0 2 -> []
adjuster "apple" 10 ’b’ -> "applebbbbb"
adjuster "apple" 5 ’b’ -> "apple"
adjuster "apple" 2 ’b’ -> "le"
adjuster [] 3 (7,4) -> [(7,4),(7,4),(7,4)]

我做了什么:

adjuster (x:xs) count b 
        | count < 0             = error "Invalid Size"
        | count == 0            = []
        | count < length xs     = adjuster xs (count-1) b
        | otherwise             = (adjuster xs (count-1) b):b

我遇到的错误:

 * Occurs check: cannot construct the infinite type: t ~ [t]
      Expected type: [t]
        Actual type: [[t]]
    * In the expression: (adjuster xs (count - 1) b) : b
      In an equation for `adjuster':
          adjuster (x : xs) count b
            | count < 0 = error "Invalid Size"
            | count == 0 = []
            | count < length xs = adjuster xs (count - 1) b
            | otherwise = (adjuster xs (count - 1) b) : b
    * Relevant bindings include
        b :: [[t]] (bound at code01.hs:21:23)
        adjuster :: [a] -> Int -> [[t]] -> [t] (bound at code01.hs:21:1)

我是 haskell.I 的新人,非常感谢您的帮助。

您正在尝试在列表中的列表中构建列表,依此类推……

这是为什么?

(:) :: a -> [a] -> [a]

冒号运算符将一个元素和此类元素的列表作为参数,并从中构造一个列表(通过在该元素前加上)。

在你的情况下,如果 (adjuster ...) 的类型为 [a],则 b 的类型必须为 [[a]],第 4 行与最终结果相同,但是第 3 行说类型是 [a] - 这是不同的。这就是 GHC 试图告诉你的。

如何解决?

首先,为每个顶级函数添加类型签名始终是一个好建议:

adjuster :: [a] -> Int -> a -> [a]

在实现您的功能时,这应该会清除您的错误消息并让您保持诚实。

那么如何解决这个问题:- 您可以使用 b:adjuster xs (count-1) b 但这会产生错误顺序的结果 - 所以

选择不同的运算符:(++) 并将 b 包装在列表中。

    | otherwise             = (adjuster xs (count-1) b)++[b]

现在还有一些提示:

  • 编译文件时打开 -Wall - 这会告诉你你错过了 adjuster [] .. 的情况。
  • 使用 length 是一个相对昂贵的操作 - 因为它需要遍历要计算的完整列表。
  • 作为练习 - 尝试修改您的函数以不使用 length,但仅使用基本情况 [] 用于列表,0 用于 count(此处函数 replicate 可能会有帮助)。

这是另一种方法,没有错误处理

adjuster xs n v = tnr n $ (++) (replicate n v) $ tnr n xs
      where tnr n r = take n $ reverse r

如果你玩签名,也许这样更干净

adjuster n v = tnr . (++) (replicate n v) . tnr
             where tnr = take n . reverse