【问题标题】:Haskell permutation function does not compileHaskell 置换函数无法编译
【发布时间】:2014-11-29 03:28:14
【问题描述】:

我正在复习一些 Haskell,我正在尝试编写一个置换函数来映射 [1,2,3] -> [[1,2,3], [1,3,2], [ 2,1,3],[2,3,1],[3,1,2],[3,2,1]]。我有以下 -

permute:: [a] -> [[a]]
permute [] = []
permute list = map f list
        where
                f x = listProduct x (permute (exclude x list))
                exclude e list1 = filter (/= e) list1
                listProduct x list2 = map (x :) list2

以下是我得到的错误信息-

permutations.hs:3:20:
    Couldn't match type `a' with `[a]'
      `a' is a rigid type variable bound by
          the type signature for permute :: [a] -> [[a]]
          at permutations.hs:1:11
    Expected type: a -> [a]
      Actual type: a -> [[a]]
    In the first argument of `map', namely `f'
    In the expression: map f list
    In an equation for `permute':
        permute list
          = map f list
          where
              f x = listProduct x (permute (exclude x list))
              exclude e list1 = filter (/= e) list1
              listProduct x list2 = map (x :) list2
Failed, modules loaded: none.

我会尝试调试,但它甚至无法编译。有什么想法吗?

【问题讨论】:

  • 它在为你调试,说它期望 f 是 a -> [a] 类型的函数,但得到的是 a -> [[a]]
  • listProduct 任何看起来都应该返回[[a]],这将使f 接受参数x 并返回[[a]]。也许尝试独立地试验每个功能,以确保它做你想做的事情。
  • Gilad,为什么 f 应该是 (a -> [a]) 类型?根据 map 的定义,似乎 f 有权从和映射到完全多态类型 - map :: (a->b) -> [a] -> [b] map f [] = [] map f (x:xs) = f x : map f xs
  • 您应该在fexcludelistProduct 上添加类型签名。当你有类型签名时的编译器错误会给你更多关于哪里出错的线索。
  • @TheCriticalImperitive 通常是个好主意,尽管在这种特殊情况下需要ScopedTypeVariables 扩展,实际上并没有任何帮助。

标签: debugging haskell types compiler-errors permutation


【解决方案1】:

让我们只关注所涉及的列表类型:

permute (exclude x list)

因为permute的类型签名,所以是[[a]]类型,因此

listProduct x (permute (exclude x list))

也是 [[a]] 的类型。 listProduct

listProduct x list2 = map (x :) list2

总结,

 f x = listProduct x (permute (exclude x list))

返回[[a]],然后

permute list = map f list

f 应用于[a] 的所有元素,返回[[[a]]], 这不是 permute 的正确返回类型。

如何解决

  1. 通过连接所有列表将 [[[a]]] 转换为 [[a]]
  2. 添加一个Eq a 约束,因为您在exclude 中使用/= x
  3. 当前基本情况表明空列表没有排列,这是错误的。 [] 有一种排列。 (确实,0!=1,而不是 0)

【讨论】:

  • 嘿,所以我不确定我是否同意最后的评论。我们将f 应用于list 中的每个 元素,而不是整个list;也就是说,我们将f 应用于a 类型的值,而不是[a]。至少这是我的意图。
  • 所以我们应该返回[[a]],而不是[[[a]]]
  • @DanSok 如果flist 的每个元素返回一个[[a]],则map f list 的结果是[[[a]]]
【解决方案2】:

对于任何可能感兴趣的人 - 为了解决这个问题,我需要一种方法来模拟命令式编程的迭代,因此建议了一个循环列表(基本上我一直在尝试模拟我曾经用 javascript 编写的解决方案,其中涉及与我描述的过程相同,唯一的例外是我利用了 for 循环)。

permute [] = [[]]
permute list = [h:tail | h <- list, tail <- (permute (exclude h list))]
  where
    exclude x = filter (/= x)

不一定是最有效的解决方案,因为exclude 是一个O(n) 操作,但很简洁,并且作为概念证明工作得很好。

【讨论】:

    【解决方案3】:

    做到这一点的“正确”方法是将列表项的选择和排除组合到一个纯粹的位置操作select :: [a] -&gt; [(a,[a])]

    import Control.Arrow (second)
    -- second f (a, b) = (a, f b)
    
    select [] = []
    select (x:xs) = (x,xs) : map (second (x:)) (select xs)
    
    permute [] = [[]]    -- 1 permutation of an empty list
    permute xs = [x : t | (x,rest) <- select xs, t <- permute rest] 
    

    要“调试”- 开发您的程序,您可以将define each internal function on its own 作为一个全局程序,并查看各个部分是否适合:

    > let exclude e list1 = filter (/= e) list1
    > let listProduct x list2 = map (x :) list2
    > let f x = listProduct x (permute (exclude x list)) 
    <interactive>:1:25: Not in scope: `permute' -- permute is not defined yet!!
    <interactive>:1:44: Not in scope: `list'    -- need to pass 'list' in
    > let f list x = listProduct x (undefined (exclude x list))
                                    ---------   -- use a stand-in for now
    > let permute [] = [] ; permute list = map (f list) list
    > :t permute                           ---
    permute :: (Eq t) => [t] -> [[[t]]]    -- one too many levels of list!
    

    所以它们确实适合,只是结果不是我们想要的。我们可以更改其结果的组合方式,而不是更改f 生成的内容(如编译器建议的那样)。 concat 删除了一级列表嵌套(它是 [] 类型构造函数的一元 join):

    > let permute [] = [] ; permute list = concatMap (f list) list
    > :t permute                           ---------
    permute :: (Eq t) => [t] -> [[t]]      -- much better
    

    顺便说一句,如果您没有自己指定类型签名,它会编译并将[a] -&gt; [[[a]]] 类型报告给您。

    更重要的是,通过将/= 引入图片,您无需对列表中的项目使用Eq a 约束:permute :: (Eq a) =&gt; [a] -&gt; [[a]]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多