【问题标题】:infinite type error in haskell when trying to translate python function into haskell. Why?尝试将 python 函数转换为 haskell 时,haskell 中出现无限类型错误。为什么?
【发布时间】:2015-09-30 08:27:34
【问题描述】:
def get_N_Partition_Permutations(xs, n):
    if n == 1:
        return [[xs]]
    acc = []
    for i in xrange(1,len(xs)):
        acc += [[xs[:i]] + j for j in get_N_Partition_Permutations(xs[i:], n-1)]
    return acc

我正在尝试在下面的 haskell 中实现上面的函数(在 Python 中)。

getNPartitionPermutations :: [a] -> Int -> [[[a]]]
getNPartitionPermutations xs 1 = [[xs]]
getNPartitionPermutations xs n = iter xs 1 []
  where iter ys i acc
          | length xs == i = acc
          | otherwise      =
              iter ys (i+1) (elem':acc)
                where elem' = map (\x -> [(take i ys)]:x) rec'
                      rec' = getNPartitionPermutations (drop i ys) (n-1)

我遇到了一个我不完全理解的奇怪错误。为什么这段代码在 python 中有效,但在 haskell 中无效?错误信息如下

partitionArr.hs|23 col 104 error| Occurs check: cannot construct the infinite type: a ~ [[a]]
Expected type: [[[a]]]
Actual type: [a]
Relevant bindings include
  acc :: [[[[[a]]]]] (bound at partitionArr.hs:21:19)
  ys :: [a] (bound at partitionArr.hs:21:14)
  iter :: [a] -> GHC.Types.Int -> [[[[[a]]]]] -> [[[[[a]]]]] (bound at partitionArr.hs:21:9)
  xs :: [[[a]]] (bound at partitionArr.hs:20:27)
  getNPartitionPermutations :: [[[a]]] -> GHC.Types.Int -> [[[[[a]]]]]
  (bound at partitionArr.hs:19:1)
  In the first argument of ‘Algo.getNPartitionPermutations’,
    namely ‘(GHC.List.drop n ys)’
  In the second argument of ‘(GHC.Base.$!)’,
    namely ‘Algo.getNPartitionPermutations (GHC.List.drop n ys) (n
    GHC.Num.- 1)’

partitionArr.hs|20 col 39 error| Occurs check: cannot construct the infinite type: a ~ [[a]]
Expected type: [a]
Actual type: [[[a]]]
Relevant bindings include
  iter :: [a] -> GHC.Types.Int -> [[[[[a]]]]] -> [[[[[a]]]]] (bound at partitionArr.hs:21:9)
  xs :: [[[a]]] (bound at partitionArr.hs:20:27)
  getNPartitionPermutations :: [[[a]]] -> GHC.Types.Int -> [[[[[a]]]]]
  (bound at partitionArr.hs:19:1)

In the first argument of ‘iter’, namely ‘xs’In the expression: iter xs 1 []

编辑:因为我不清楚。 python 函数所做的是返回列表的所有可能的 n 分区。所以参数 [1,2,3,4],2 给出 [[[1],[2,3,4]],[[1,2],[3,4]],[[1,2,3 ][4]]]

haskell 函数的类型签名是 [a] -> Int -> [[[a]]]

【问题讨论】:

  • 消息您的列表嵌套级别不匹配。尝试向您的函数添加显式类型签名;那么 GHC 就会知道您打算的类型是什么,并且可能能够让您更好地了解错误在哪里。
  • 我个人的理论是你不需要map (\x -> [(take n ys)]:x) 中的方括号,但我没有检查过。
  • 仅作记录:您的 Python 代码中缺少 subdivideList 的定义。
  • 啊我错了,这是一个递归调用。

标签: python algorithm haskell


【解决方案1】:

首先,我让您的 Haskell 代码更易于理解:

getNPartitionPermutations :: [a] -> Int -> [[[a]]]
getNPartitionPermutations xs 1 = [[xs]]
getNPartitionPermutations xs n = iter xs 1 []
      where iter ys n acc
              | length xs == n = acc
              | otherwise      =
                  iter ys (n+1) (elem:acc)
                    where elem = map (\x -> [(take n ys)]:x) rec'
                          rec' = getNPartitionPermutations (drop n ys) (n-1)

看起来类型问题来自elem定义中的这个表达式:

[(take n ys)]:x

如果将其替换为 head xtake n ystake n ys ++ x,则代码编译。这表明您以某种方式提供了[[[a]]] 类型的值,而不是[a] 类型的值。也就是说,您有 2 个额外的 [] 包装。

虽然我没有花时间完全理解您的代码的用途,但我确信通过这些提示您可以找出问题所在。

编辑:问题是使用: 而不是++,以及[take n ys] 中不必要的包装,所以用take n ys ++ x 替换是要走的路。 (只是将 cmets 合并到答案中)


一般建议:

跟踪/查明类型错误的方法是首先按照我的方式重构代码,即拆分大型表达式并为子表达式命名,以便它们的含义变得更加明显,因此您可以临时替换某些部分使用undefined 的整体表达式,因为undefined 具有您喜欢的任何类型,因此允许您编译代码而无需一次性弄清楚所有代码。例如,这是我在尝试head xtake n ys(注意(\x -> undefined) 位)之前结束的地方:

getNPartitionPermutations :: [a] -> Int -> [[[a]]]
getNPartitionPermutations xs 1 = [[xs]]
getNPartitionPermutations xs n = iter xs 1 []
      where iter ys n acc
              | length xs == n = acc
              | otherwise      =
                  iter ys (n+1) (elem:acc)
                    where elem = map (\x -> undefined) rec'
                          rec' = getNPartitionPermutations (drop n ys) (n-1)

——这是仍在编译的原始代码的最大子集。

在此之前,我有:

getNPartitionPermutations :: [a] -> Int -> [[[a]]]
getNPartitionPermutations xs 1 = [[xs]]
getNPartitionPermutations xs n = iter xs 1 []
      where iter ys n acc = undefined

之后我逐渐开始重新引入原始位,将 undefined 位移到代码树的下方:

getNPartitionPermutations :: [a] -> Int -> [[[a]]]
getNPartitionPermutations xs 1 = [[xs]]
getNPartitionPermutations xs n = iter xs 1 []
      where iter ys n acc
              | length xs == n = acc
              | otherwise      = undefined

然后

getNPartitionPermutations :: [a] -> Int -> [[[a]]]
getNPartitionPermutations xs 1 = [[xs]]
getNPartitionPermutations xs n = iter xs 1 []
      where iter ys n acc
              | length xs == n = acc
              | otherwise      =
                  iter ys (n+1) (elem:acc)
                    where elem = undefined
                          rec' = undefined

等等。

【讨论】:

  • 这是一个很好的答案。问题是当我用 [(take n ys)]:x 替换为 (take n ys):x 运行更正的代码时,它不会为我编译。此外,我认为这样做会产生不正确的结果。 haskell 的这一部分,“[(take n ys)]:x”,是从 python 代码中的“[xs[:i]] + j”翻译而来的(经过验证可以工作)。我实际上是在进行从 python 到 haskell 尾递归迭代的一对一转换。这就是我对这段代码的困扰。更奇怪的是,错误信息中提到了无限类型。大多数答案都没有解决这个问题。
  • 我没有说替换为(take n ys):x,而是take n ys。但这并不意味着代码会按照您的期望进行。尝试例如take n ys ++ x。你是了解这个领域的人,我只提供了通用的、类型相关的帮助。
  • 仅供参考:: 将一个元素添加到列表中;它不是列表连接(Haskell 中的++ == Python 中的+)。
【解决方案2】:
getNPartitionPermutations :: Num a => [a] -> Int -> [[[a]]]
getNPartitionPermutations xs 1 = [[xs]]
getNPartitionPermutations xs n = iter xs 1 []
      where iter ys i acc
              | length xs == i = acc
              | otherwise      =
                  iter ys (i+1) (elem' ++ acc)
                    where elem' = map (\x -> take i ys : x) rec'
                          rec' = getNPartitionPermutations (drop i ys) (n-1)

上面的代码可以工作。这个错误很大程度上是因为我在 (++) 更合适时使用 (:)。 Erik Allik 真的帮助我得出了这个答案,所以请把你的观点指向他,因为他对调试 haskell 的解释并指出 (++) 而不是 (:) 相当于 python (+) 有助于帮助我解决这个问题.

【讨论】:

  • 你可以接受我的回答,而不是重定向投票:)
  • 您的答案不是最终的或正确的答案。编辑:我还是这样做了。谢谢。
  • 其实它是正确的答案:你的问题是为什么会发生错误而不是工作解决方案是什么,只是为了记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 2012-09-29
  • 1970-01-01
  • 2013-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多