如何在Haskell中为不同类型定义函数? 给定
func :: Integral a => a -> a
func x = x
func' :: (RealFrac a , Integral b) => a -> b
func' x = truncate x
如何将它们组合成一个带有签名的函数
func :: (SomeClassForBoth a, Integral b) => a -> b
答案 0 :(得分:4)
使用类型类。
class TowardsZero a where towardsZero :: Integral b => a -> b
instance TowardsZero Int where towardsZero = fromIntegral
instance TowardsZero Double where towardsZero = truncate
-- and so on
可能一个具有相关类型系列约束的类更接近您所写的内容(尽管可能不会更接近您的想法):
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts
class TowardsZero a where
type RetCon a b :: Constraint
towardsZero :: RetCon a b => a -> b
instance TowardsZero Int where
type RetCon Int b = Int ~ b
towardsZero = id
instance TowardsZero Double where
type RetCon Double b = Integral b
towardsZero = truncate
-- and so on
答案 1 :(得分:2)
我不建议这样做,但你可以用GADT破解它:
data T a where
T1 :: a -> T a
T2 :: RealFrac a => a -> T b
func :: Integral a => T a -> a
func (T1 x) = x
func (T2 x) = truncate x
T
类型说:“要么你已经知道我正在包装的值的类型,要么它是RealFrac
的一些未知实例”。 T2
构造函数存在量化a
并打包RealFrac
字典,我们在func
的第二个子句中使用该字典将(未知)a
转换为b
。然后,在func
中,我将Integral
约束应用于a
,T
可能在SRCFILES := $(wildcard */*.c)
EXECFILES := $(join $(addsuffix executables/,$(dir $(SRCFILES))), $(basename $(notdir $(SRCFILES))))
内,也可能不在dir1/executables/q1)
内。
答案 2 :(得分:2)
这称为 ad hoc多态,您可以根据类型执行不同的代码。在Haskell中完成此操作的方法是使用类型类。最直接的方法是定义一个新类
class Truncable a where
trunc :: Integral b => a -> b
然后你可以定义几个具体的实例。
instance Truncable Integer where trunc = fromInteger
instance Truncable Double where trunc = truncate
这是不满意的,因为当实际上只有两个外观相同的实例时,它需要每个具体类型的实例。不幸的是,由于技术原因(能够像这样定义“实例族”干扰类型推断的开放世界假设,以及类型推断的其他困难),这是难以减少样板的情况之一。作为复杂性的提示,请注意您的定义假定没有RealFrac
和Integral
类型,但这不能保证 - 在这种情况下我们应该选择哪种实现?
此类型类解决方案还有另一个问题,即Integral
版本没有类型
trunc :: Integral a => a -> a
如您所指定,而是
trunc :: (Integral a, Integral b) => a -> b
在语义上这不是问题,因为我不相信有可能最终得到一些多态代码,你不知道你正在使用的类型是Integral
,但你确实需要要知道它是什么时候,结果类型与传入类型相同。也就是说,我声称无论何时您需要前者而不是后者签名,您都已经知道足以在源中替换trunc
id
。 (虽然这是一种直觉,我希望被证明是错误的,似乎是一个有趣的谜题)
然而,可能存在性能影响,因为您可能会不必要地调用fromIntegral
将类型转换为自身,我认为解决这个问题的方法是使用{-# RULES #-}
definitions,这是一个黑暗可怕的包我从未真正挖过的复杂性,所以我不知道这有多么难或多么容易。