簡體   English   中英

Haskell置換功能無法編譯

[英]Haskell permutation function does not compile

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

我會嘗試調試,但它甚至無法編譯。 有任何想法嗎?

讓我們僅關注涉及的列表類型:

permute (exclude x list)

由於permute的類型簽名而為[[a]]類型,因此

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約束,因為您在exclude使用/= x
  3. 當前的基本情況是,空列表沒有排列,這是錯誤的。 []有一個排列。 (的確是0!= 1,而不是0)

對於可能感興趣的任何人-為了解決此問題,我需要一種方法來模擬命令式編程的迭代,因此,建議使用一個循環列表(本質上,我一直在嘗試模擬我用javascript寫過的解決方案,而該解決方案涉及相同的過程,描述,唯一的例外是我利用了for循環)。

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

不一定是最有效的解決方案,因為excludeO(n)運算,但是很簡潔,並且可以很好地用作概念證明。

做到這一點的“正確”方法是將挑選和排除列表項組合為一個純位置操作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] 

要“調試”-開發您的程序,您可以將每個內部函數自己定義為全局函數 ,並查看各部分是否組合在一起:

> 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] -> [[[a]]]類型。

更重要的是,通過將/=放入圖片中,您不需要對列表中的項目使用Eq a約束: permute :: (Eq a) => [a] -> [[a]]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM