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

时间:2018-05-09 04:28:15

标签: haskell

我是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

1 个答案:

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

因此,yn具有相同的类型,因为我们使用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]