重载函数签名haskell

时间:2011-05-25 03:29:12

标签: haskell type-signature

编译时收到以下错误消息:

  

重复类型签名:
  weightedMedian.hs:71:0-39:findVal :: [ValPair] - >双 - >双
  weightedMedian.hs:68:0-36:findVal :: [ValPair] - > Int - >双

我的解决方案是找到findValI和findValD。但是,findValI只是将Int类型转换为Double并调用findValD。

此外,我无法在Num(Int,Double)类型上进行模式匹配,因此我不能只将类型签名更改为

findVal :: [ValPair] -> Num -> Double   

在许多语言中,我不需要不同的名字。为什么我在Haskell中需要不同的名字?这会很难添加到语言中吗?或者那里有龙吗?

5 个答案:

答案 0 :(得分:32)

特殊多态(和名称重载)在Haskell中由类型类提供:

class CanFindVal a where
          findVal :: [ValPair] -> a -> Double

instance CanFindVal Double where
     findVal xs d = ...

instance CanFindVal Int where
     findVal xs d = findVal xs (fromIntegral d :: Double)

请注意,在这种情况下,由于findVal“确实”需要一个Double,我只需要一个双倍,当我需要传递一个int时,只需使用{ {1}}在通话网站上。当涉及到实际上不同的行为或逻辑时,通常需要类型类,而不是混乱。

答案 1 :(得分:16)

支持findVal :: [ValPair] -> Double -> DoublefindVal :: [ValPair] -> Int -> Double需要ad-hoc多态(请参阅http://www.haskell.org/haskellwiki/Ad-hoc_polymorphism),这通常很危险。原因是ad-hoc多态允许使用相同的语法更改语义。

Haskell更喜欢所谓的参数多态。你总是会看到类型签名,你有一个类型变量。

Haskell通过类型类支持更安全的ad-hoc多态性版本。

您有三种选择。

  1. 使用显式函数名称继续您正在执行的操作。这是合理的,它甚至被一些c库使用,例如opengl。
  2. 使用自定义类型。这可能是最好的方式,但是很重,需要相当数量的代码(通过haskells非常紧凑的标准)。看看sclv的代码答案。
  3. 尝试使用现有的类型类(如果使用GHC),可以通过专业化获得性能。
  4. 像这样:

    findVal :: Num a => [ValPair] -> a -> Double
    {-# SPECIALISE findVal :: [ValPair] -> Int -> Double #-}
    {-# SPECIALISE findVal :: [ValPair] -> Double -> Double #-}
    findVal = ...
    

答案 2 :(得分:6)

Haskell不支持C ++样式的重载(好吧它与类型类有关,但我们不以同样的方式使用它们)。是的,有一些龙与添加它有关,主要与类型推断有关(变成指数时间或不可判断的或类似的东西)。但是,在Haskell中看到像这样的“方便”代码是非常罕见的。哪一个是Int还是Double?由于您的Int方法委托给Double方法,我的猜测是Double是“正确的”方法。只需使用那个。由于文字重载,您仍然可以将其称为:

findVal whatever 42

42将被视为Double。唯一可以解决的问题是如果你在某处从根本上一个Int,你需要将它作为这个参数传递。然后使用fromIntegral。但是如果你努力让你的代码在任何地方使用“正确”的类型,这种情况将是不常见的(当你必须转换时,值得引起注意)。

答案 3 :(得分:3)

在这种情况下,我认为编写一个处理第二个参数的Int和Double的函数很容易。只需编写findVal,以便在第二个参数上调用realToFrac。这会将Int转换为Double,只留下Double。然后让编译器为你推断出类型,如果你是懒惰的。

答案 4 :(得分:0)

在许多其他编程语言中,您可以声明(种类)具有相同名称但签名中具有不同其他内容的函数,例如不同的参数类型。这称为重载,当然也是实现ad-hoc多态的最常用方法。

Haskell故意不支持重载,因为它的设计者并不认为它是实现ad-hoc多态的最佳方法。 Haskell方式是受约束的多态,它涉及声明类型类和类实例