Haskell - 将整数列表映射到它们的平方根

Ste*_*n.W 2 haskell

我创建了一个小函数,将整数列表映射到它们的平方根。代码本身很简单:

f x = map sqrt [1..x]
Run Code Online (Sandbox Code Playgroud)

使用默认类型推断,它可以成功加载,但该函数可以接受Floating类型类值,而我只是希望它接受Integers。所以我在它上面添加了一个类型注释。

f :: (Integral a, Floating b) => a -> [b]
f x = map sqrt [1..x]
Run Code Online (Sandbox Code Playgroud)

出乎我的意料,加载失败。在 GHCi 的 REPL 中抛出错误:

1.hs:48:7: error:
    • Couldn't match type ‘a’ with ‘b’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          f :: forall a b. (Integral a, Floating b) => a -> [b]
        at 1.hs:47:1-41
      ‘b’ is a rigid type variable bound by
        the type signature for:
          f :: forall a b. (Integral a, Floating b) => a -> [b]
        at 1.hs:47:1-41
      Expected type: [b]
        Actual type: [a]
    • In the expression: map sqrt [1 .. x]
      In an equation for ‘f’: f x = map sqrt [1 .. x]
    • Relevant bindings include
        x :: a (bound at 1.hs:48:3)
        f :: a -> [b] (bound at 1.hs:48:1)
   |
48 | f x = map sqrt [1..x]
   |       ^^
Run Code Online (Sandbox Code Playgroud)

我完全失去了理智,不知道错误在说什么。似乎抱怨结果类型应该是[a]而不是[b]. 但这是荒谬的,因为它a是类型 class 的成员Integral,并且该函数肯定会返回一个Floating数字列表。它只是没有任何意义。

谁能解释为什么会发生错误,我该如何解决?

Wil*_*sem 9

问题是sqrt :: Floating a => a -> a总是将数字映射到相同类型的数字,注意a -> a类型签名中的 。它还要求数字是 的实例Floating,尽管从技术上讲,您可以创建同时是Integral和实例的类型Floating,但这没有多大意义。

如果您编写,[ 1 .. x ]则会生成与x. 因此,如果xIntegral a => a,则[ 1 .. x ]具有类型Integral a => [a](并且是相同的a)。但是,您的类型签名表示,对于每种Integral类型a,您都可以生成某个Floating类型的任何元素列表b

您可以利用fromIntegral :: (Integral a, Num b) => a -> b将整数转换为另一种类型的数字,因此您可以将其写为:

f :: (Integral a, Floating b) => a -> [b]
f x = map (sqrt . fromIntegral) [1..x]
Run Code Online (Sandbox Code Playgroud)