我是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]
请注意"枚举"而不是"积分"。
我想我可以摆脱类型签名,但我的印象是放置签名是一种很好的做法,并且我正在尝试解决一个更大的问题,我在这里报告错误: 由于使用"it"而产生的不明确类型变量"a0">
如果我让这部分工作,我会发布一个单独的问题!
请让我知道我是否最好发帖到另一个组,或者我是否应该发布更多信息。
-戴夫
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
s具有与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]