我是Haskell的新手。我把它键入WinGHCi并且工作正常:
> let x = 0.5
> let n = 5
> map (\y->(x**y)) [0..n]
[1.0,0.5,0.25,0.125,6.25e-2,3.125e-2] -- notice it is powers of 1/2 !
但是当我在文件中定义一个简单的函数时:
powersOfx :: (Integral a, Floating b) => a -> b -> [b]
powersOfx n x = map (\y->(x**y)) [0..n]
并输入
:l myFile
,我明白了:
Couldn't match expected type ‘b’ with actual type ‘a’
‘a’ is a rigid type variable bound by
the type signature for:
powersOfx :: forall a b. (Integral a, Floating b) => a -> b -> [b]
发生了什么?我签名不正确吗?我猜我可能是,因为当我只是评论它时:l myFile它可以工作但是
:t powersOfx
我明白了:
powersOfx :: (Floating b, Enum b) => b -> b -> [b]
注意' Enum'而不是积分'
我想我可以摆脱类型签名,但我认为签名是一种很好的做法,我试图解决一个更大的问题。 ;我在这里报告错误: Ambiguous type variable `a0' arising from a use of `it'
如果我让这部分工作,我会发布一个单独的问题!
如果我发布到其他论坛或者我应该发布更多信息,请告诉我。
-Dave
答案 0 :(得分:3)
map (\y->(x**y)) [0..n]
函数 简而言之:您的签名太宽,可以设计Floating
类型,以便无法调用该函数。
让我们首先分析您在这里使用的类型:
Prelude> let x = 0.5
Prelude> let n = 5
Prelude> :t map (\y->(x**y)) [0..n]
map (\y->(x**y)) [0..n] :: (Enum b, Floating b) => [b]
Prelude> :t \n x -> map (\y->(x**y)) [0..n]
\n x -> map (\y->(x**y)) [0..n]
:: (Enum b, Floating b) => b -> b -> [b]
所以我们在这里看到的是输出类型b
,实际上必须是两个类型类的实例:Enum
和Floating
。这是合乎逻辑的:你使用[0..n]
,这意味着你要求Haskell枚举0
和n
之间的所有元素,但是一个数字本身不是可枚举的(实际上我们已经可以我想知道Floating
首先是Enum
:我们在这里制作一个跳跃,但我们因此省略了Floating
之间的值,以防我们有一个真正的浮点数,然后枚举甚至是不可能的。)
因此,y
与n
具有相同的类型,因为我们使用x
和y
执行算术运算(我们编写x ** y
) ,这意味着x
和y
需要具有相同的类型,因为(**)
具有类型(**) :: Floating a => a -> a -> a
。因此我们可以构建一个函数:
powersOfx :: (Enum b, Floating b) => b -> b -> [b]
powersOfx n x = map (\y->(x**y)) [0..n]
但这是一个坏主意。 Floating
通常是我们最好尽可能避免的事情:如果数量很大,我们可能会出现各种舍入错误。我们可以使用fromIntegral :: (Integral a, Num b) => a -> b
,但是当我们将例如较大的Int
转换为Float
时,这可能会导致舍入错误。在这种情况下,类型将是:
powersOfx :: (Enum b, Floating b, Integral a) => a -> b -> [b]
powersOfx n x = map (\y->(x**y)) [0..fromIntegral n]
尽管如此,我们可以使用iterate :: (a -> a) -> a -> [a]
并使用take :: Int -> [a] -> [a]
(或genericTake :: Integral i => i -> [a] -> [a]
)来使功能更灵活,更通用:
import Data.List(genericTake)
powersOfx :: (Integral i, Num n) => i -> n -> [n]
powersOfx n x = genericTake (n+1) (iterate (x*) 1)
然后产生:
Prelude Data.List> f 5 0.5
[1.0,0.5,0.25,0.125,6.25e-2,3.125e-2]