2012-01-17 60 views
6

背景:我正在研究匿名遞歸,並且我正在接受實現前奏的挑戰,而不使用任何命名遞歸,只是爲了幫助它在我的腦海中很好地坐下來。我還沒到那裏,一路上我遇到了一些無關但仍然有趣的事情。等效函數產生不同的解釋結果

map1  = \f -> \x -> if (tail x) == [] 
         then [f (head x)] 
         else f (head x) : (map1 f (tail x)) 

map2 f x =    if (tail x) == [] 
         then [f (head x)] 
         else f (head x) : (map2 f (tail x)) 

map3 f (x:xs) = if xs == [] then [f x] else f x : (map3 f xs) 

map4 f (x:[]) = [f x] 
map4 f (x:xs) = f x : map4 f xs 

GHC抱怨第一個,第二個是好的,第三個和第四個只是爲了展示他們如何實現不同。

*Main> map1 (*2) [1..10] 

<interactive>:1:15: 
    No instance for (Num()) 
     arising from the literal `10' 
    Possible fix: add an instance declaration for (Num()) 
    In the expression: 10 
    In the second argument of `map1', namely `[1 .. 10]' 
    In the expression: map1 (* 2) [1 .. 10] 
*Main> map2 (*2) [1..10] 
[2,4,6,8,10,12,14,16,18,20] 
*Main> map3 (*2) [1..10] 
[2,4,6,8,10,12,14,16,18,20] 
*Main> map4 (*2) [1..10] 
[2,4,6,8,10,12,14,16,18,20] 

如果我向map1添加一個類型簽名,那就很好。

map1 :: Eq a => (a -> b) -> [a] -> [b] 

前兩個函數看起來幾乎相同的給我,所以我想我的問題很簡單「這是怎麼回事?」

+2

我不確定您是否有以這種方式編寫的具體原因。爲什麼不使用[]作爲遞歸的基本情況而不是(x:[])?你的任何函數都不能用於空列表。 – 2012-01-17 01:17:10

回答

12

你被咬了。任何寫作爲foo = ...的意思 - 表示沒有定義的參數,並且沒有給出顯式類型 - 根據此限制必須具有非泛型類型。正如你所說的,在這種情況下泛型類型必須是Eq a => (a -> b) -> [a] -> [b],但由於單態限制適用,所以ab都被替換爲(),這是可用於可用類型變量的最簡單的類型。

6

但是,如果你使用不受約束null代替(== [])

Prelude> let map0 = \f -> \x -> if null (tail x) then [f (head x)] else f (head x) : map0 f (tail x) 
Prelude> :t map0 
map0 :: (a -> t) -> [a] -> [t] 
Prelude> map (*2) [1 .. 10] 
[2,4,6,8,10,12,14,16,18,20] 

它的工作原理不帶參數或者簽名。 只有約束型變量受到單態限制的限制。

如果你把map1定義成一個文件,並嘗試編譯或將其加載到ghci中,

Ambiguous type variable `a0' in the constraint: 
    (Eq a0) arising from a use of `==' 
Possible cause: the monomorphism restriction applied to the following: 
    map1 :: forall t. (a0 -> t) -> [a0] -> [t] (bound at Maps.hs:3:1) 
Probable fix: give these definition(s) an explicit type signature 
       or use -XNoMonomorphismRestriction 
In the expression: (tail x) == [] 
In the expression: 
    if (tail x) == [] then 
     [f (head x)] 
    else 
     f (head x) : (map1 f (tail x)) 
In the expression: 
    \ x 
    -> if (tail x) == [] then 
      [f (head x)] 
     else 
      f (head x) : (map1 f (tail x)) 

ghci中只有它確實是因爲它使用ExtendedDefaultRules的方式抱怨,否則你將有得到了一個可以理解的錯誤信息。

相關問題