Haskell置换函数不编译

时间:2014-10-04 04:33:33

标签: debugging haskell types compiler-errors permutation

我正在刷新一些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.

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

3 个答案:

答案 0 :(得分:2)

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

permute (exclude x list)
由于[[a]]的类型签名,

属于permute,因此

listProduct x (permute (exclude x list))
def也是类型[[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约束,因为您在/= x中使用exclude
  3. 基本案例当前表明空列表没有排列,这是错误的。 []有一个排列。 (确实,0!= 1,而不是0)

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

执行此操作的“正确”方法是将列表项的拾取和排除合并为一个纯粹的位置操作select :: [a] -> [(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类型构造函数的monadic []

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

顺便说一下,如果您自己指定类型签名,它会编译并向您报告[a] -> [[[a]]]类型。

更重要的是,通过将/=置于图片中,您不必要对列表中的项目Eq a约束:permute :: (Eq a) => [a] -> [[a]]