2012-01-17 59 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的方式抱怨,否则你将有得到了一个可以理解的错误信息。

相关问题