哈斯克尔.加载函数时键入错误,但不是内联



我是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,实际上必须是两个类型类的实例:EnumFloating。这是合乎逻辑的:你使用[0..n],所以这意味着你要求 Haskell 枚举0n之间的所有元素,但一个数字本身不是可枚举的(事实上我们已经可以怀疑Floating首先是可Enum的:在这里我们制作一个跃点,但我们因此省略了两者之间的Floating值, 如果我们有一个真正的浮点数,那么枚举甚至是不可能的(。

因此,ys具有与n相同的类型,并且由于我们使用xy执行算术(我们写x ** y(,这意味着xy需要具有相同的类型,因为(**)具有类型(**) :: 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]

最新更新