定义向量的函数在Haskell中不起作用

时间:2016-10-15 19:45:54

标签: function haskell

我是Haskell的初学者(目前正在学习模式匹配),我尝试编写简单的函数来定义向量:

vector :: (Num a) => a -> a -> String
vector 0 0 = "This vector has 0 magnitude."
vector x y = "This vector has a magnitude of " ++ show(sqrt(x^2 + y^2)) ++ "."

但是我得到一堆我根本不理解的错误。

helloworld.hs:9:8: error:
    • Could not deduce (Eq a) arising from the literal ‘0’
      from the context: Num a
        bound by the type signature for:
                   vector :: Num a => a -> a -> String
        at helloworld.hs:8:1-37
      Possible fix:
        add (Eq a) to the context of
          the type signature for:
            vector :: Num a => a -> a -> String
    • In the pattern: 0
      In an equation for ‘vector’:
          vector 0 0 = "This vector has 0 magnitude."

helloworld.hs:10:51: error:
    • Could not deduce (Show a) arising from a use of ‘show’
      from the context: Num a
        bound by the type signature for:
                   vector :: Num a => a -> a -> String
        at helloworld.hs:8:1-37
      Possible fix:
        add (Show a) to the context of
          the type signature for:
            vector :: Num a => a -> a -> String
    • In the first argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2))’
      In the second argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
      In the expression:
        "This vector has a magnitude of "
        ++ show (sqrt (x ^ 2 + y ^ 2)) ++ "."

helloworld.hs:10:56: error:
    • Could not deduce (Floating a) arising from a use of ‘sqrt’
      from the context: Num a
        bound by the type signature for:
                   vector :: Num a => a -> a -> String
        at helloworld.hs:8:1-37
      Possible fix:
        add (Floating a) to the context of
          the type signature for:
            vector :: Num a => a -> a -> String
    • In the first argument of ‘show’, namely ‘(sqrt (x ^ 2 + y ^ 2))’
      In the first argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2))’
      In the second argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
Failed, modules loaded: none.
Prelude> :load helloworld
[1 of 1] Compiling Main             ( helloworld.hs, interpreted )

helloworld.hs:10:51: error:
    • Could not deduce (Show a) arising from a use of ‘show’
      from the context: Integral a
        bound by the type signature for:
                   vector :: Integral a => a -> a -> String
        at helloworld.hs:8:1-42
      Possible fix:
        add (Show a) to the context of
          the type signature for:
            vector :: Integral a => a -> a -> String
    • In the first argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2))’
      In the second argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
      In the expression:
        "This vector has a magnitude of "
        ++ show (sqrt (x ^ 2 + y ^ 2)) ++ "."

helloworld.hs:10:56: error:
    • Could not deduce (Floating a) arising from a use of ‘sqrt’
      from the context: Integral a
        bound by the type signature for:
                   vector :: Integral a => a -> a -> String
        at helloworld.hs:8:1-42
      Possible fix:
        add (Floating a) to the context of
          the type signature for:
            vector :: Integral a => a -> a -> String
    • In the first argument of ‘show’, namely ‘(sqrt (x ^ 2 + y ^ 2))’
      In the first argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2))’
      In the second argument of ‘(++)’, namely
        ‘show (sqrt (x ^ 2 + y ^ 2)) ++ "."’
Failed, modules loaded: none.

有人可以解释一下如何正确编写这个函数,至少vector 0 0出了什么问题?

2 个答案:

答案 0 :(得分:5)

第一个类型错误是因为您在文字0上进行了模式匹配。您只需要Num a所需的(Num a, Eq a)才能实现此目的。

第二种类型错误是因为您尝试在涉及a的计算中使用show。现在,您需要(Num a, Eq a, Show a)

第三,因为您使用了sqrt,它不在Num但在Floating,所以现在它(Num a, Eq a, Show a, Floating a)

或者,您可以完全删除类型签名并提示ghci类型:

λ> :t vector
vector :: (Show a, Floating a, Eq a) => a -> a -> [Char]

请注意,Floating隐含Num

答案 1 :(得分:3)

错误消息告诉您需要知道的一切。

Could not deduce (Eq a)

在数字文字上使用模式匹配时,它需要约束(Eq a, Num a),因为Haskell在内部使用==来对文字进行匹配。

Could not deduce (Show a)

使用show时,您需要约束(Show a),因为默认情况下并非所有类型都可以显示。

Could not deduce (Floating a)

使用sqrt等小数运算时,需要约束(Floating a),因为并非所有数值类型都支持这些运算。

全部放在一起:

vector :: (Eq a, Num a, Show a, Floating a) => a -> a -> String
vector 0 0 = "This vector has 0 magnitude."
vector x y = "This vector has a magnitude of " ++ show(sqrt(x^2 + y^2)) ++ "."

您也可以省略类型签名,然后问ghci:

> let vector 0 0 = "This vector has 0 magnitude."; vector x y = "This vector has a magnitude of " ++ show(sqrt(x^2 + y^2)) ++ "."
> :t vector
vector :: (Eq a, Floating a, Show a) => a -> a -> [Char]

在这里,您可以看到您不需要额外的Num a约束,因为FloatingNum的子类,通过Fractional。您也可以在ghci中获得有关这些类的信息:

> :info Floating
class Fractional a => Floating a where
  pi :: a
  exp :: a -> a
  log :: a -> a
  sqrt :: a -> a
  ...
        -- Defined in ‘GHC.Float’
instance Floating Float -- Defined in ‘GHC.Float’
instance Floating Double -- Defined in ‘GHC.Float’

在编写像这样的非常通用的代码时,通常必须指定您使用的所有约束。但是你也可以给这个函数一个更简单的非泛型类型,比如Double -> Double -> String