本文介绍了可能“超载”通过FlexibleInstances返回不同的类型,或者匹配类型类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 作为一个简单的测试,这里是一个例子,我们可以通过使用FlexibleInstances AdjusterType数据类型。它定义了一个 adjust 操作,根据它是否包含Integer或Double来为其值添加一个不同的值: { - #LANGUAGE FlexibleInstances# - } class可调a其中 adjust :: a - > Double 数据AdjusterType a =调整者a 派生显示 实例可调整(AdjusterType整数)其中调整(Adjuster a)= fromIntegral(a + 20) 实例可调(AdjusterType Double)其中 adjust(Adjuster a)= a + 0.04 多少可以按预期工作: Prelude> adjust(Adjuster(1000 :: Integer)) 1020.0 Prelude> adjust(Adjuster(3 :: Double)) 3.04 有可能使整数版本的 adjust 返回一个Integer,而Double版本返回Double? 一般化调整的签名并从整数大小写除去 fromIntegral 不起作用: class可调a其中 adjust :: Num n => a - > n 实例可调(AdjusterType整数)其中 adjust(Adjuster a)= a + 20 这会产生一个错误,指出n是一个刚性类型变量,它与Integer不匹配: 无法与实际类型'Integer'匹配的预期类型'n''n'是一个刚性类型变量,由绑定调整:: Num n =>的类型签名。 AdjusterType整数 - > n 相关绑定包括 adjust :: AdjusterType Integer - > n'在'(+)'的第一个参数中,即'a'在表达式中:a + 20 它在这里期望什么类型的Integer不匹配...或者没有实际的类型工作,这只是一个奇怪的错误信息? n是小写字母,所以推测它知道它不是数据类型) 实例规范中的类型约束也不会参与匹配的分辨率: 实例Integral i => Adjustable(AdjusterType i)其中 adjust(Adjuster a)= fromIntegral(a + 20) 实例RealFloat r => Adjustable(AdjusterType r)其中 adjust(Adjuster a)= a + 0.04 就像重复一样,就好像它们都是 Adjustable(AdjusterType x))。约束只适用于解析完成后。 是否有任何方法可以为类型类提供像上面这样的重载行为,或者它总是一个特定的实例? 解决方案 您可以使 Adjustable type class接受两个类型参数而不是一个,所以它会知道 AdjusterType 中的内容: class可调fa,其中 adjust :: fa - > a 然后这些实例应该是: adjust(Adjuster a)= a + 20 实例Adjustable AdjusterType Double其中 adjust(Adjuster a)p $ p $ = a + 0.04 以及ghci的一些结果: > :set + t > adjust(Adjuster(100 :: Int))< 120 >调整(Adjuster(100 :: Double)) 返回类型 adjust 的类型是 forall n。 Num n => n ,一个带有单个约束 Num 的多态类型,所以返回具体类型的函数不会输入check。使用 fromIntegral 包装你的函数将解决 fromIntegral ::(Integral a,Num b)=> a - > b 。如果您希望函数针对每种不同的类型行为不同,那么您必须添加一个实例为每个。您可以通过限制类的类型参数来添加一些默认行为: { - #LANGUAGE DeriveFunctor# - } { - #LANGUAGE MultiParamTypeClasses# - } class Extract f where extract :: fa - > a 类(Extract f,Functor f,Num a)=>可调整的f a其中 adjust :: f a - > adjust = extract。 fmap(+20) 数据AdjusterType a =调整器a 派生(Functor) 实例Extract AdjusterType其中 extract(Adjuster a)= a 实例Adjustable AdjusterType Int其中 - 不必在此处写任何代码 I'm curious about what kind of "overloading" can be accomplished in Haskell's type classes via "FlexibleInstances".As a simple test, here is a case of an AdjusterType datatype. It defines an adjust operation that will add a different amount to its value based on whether it contains an Integer or a Double:{-# LANGUAGE FlexibleInstances #-}class Adjustable a where adjust :: a -> Doubledata AdjusterType a = Adjuster a deriving Showinstance Adjustable (AdjusterType Integer) where adjust (Adjuster a) = fromIntegral (a + 20)instance Adjustable (AdjusterType Double) where adjust (Adjuster a) = a + 0.04That much works as expected:Prelude> adjust (Adjuster (1000 :: Integer))1020.0Prelude> adjust (Adjuster (3 :: Double))3.04Is it possible to make the Integer version of adjust return an Integer, and the Double version return a Double?Generalizing the signature of adjust and removing the fromIntegral on the integer case doesn't work:class Adjustable a where adjust :: Num n => a -> ninstance Adjustable (AdjusterType Integer) where adjust (Adjuster a) = a + 20This produces an error saying that "n" is a rigid type variable that doesn't match Integer:Couldn't match expected type ‘n’ with actual type ‘Integer’ ‘n’ is a rigid type variable bound by the type signature for adjust :: Num n => AdjusterType Integer -> nRelevant bindings include adjust :: AdjusterType Integer -> nIn the first argument of ‘(+)’, namely ‘a’In the expression: a + 20What type was it expecting here that Integer isn't matching...or would no type actually work and it's just a weird error message? (n is lowercase, so presumably it knows it's not a datatype)Type constraints in the instance specifications also don't appear to participate in the matching resolution:instance Integral i => Adjustable (AdjusterType i) where adjust (Adjuster a) = fromIntegral (a + 20)instance RealFloat r => Adjustable (AdjusterType r) where adjust (Adjuster a) = a + 0.04So these act like duplicates, as if they were both Adjustable (AdjusterType x)). The constraint only applies after the resolution is done.Is there any way to provide an overloaded behavior like above to a type class, or must it always be to a specific instance? 解决方案 You can make the Adjustable type class accept two type parameters instead of one, so it will know what's inside the AdjusterType:{-# LANGUAGE MultiParamTypeClasses #-}class Adjustable f a where adjust :: f a -> aThen the instances should be:instance Adjustable AdjusterType Int where adjust (Adjuster a) = a + 20instance Adjustable AdjusterType Double where adjust (Adjuster a) = a + 0.04And some results from ghci:> :set +t> adjust (Adjuster (100 :: Int))< 120< it :: Int> adjust (Adjuster (100 :: Double))< 100.04< it :: DoubleThe return type of adjust is of type forall n . Num n => n, a polymorphic type with a single constraint Num, so your function returning a concrete type won't type check. Wrap your function with fromIntegral will solve the problem since fromIntegral :: (Integral a, Num b) => a -> b.If you expect the function to behave differently for every distinct type, yes you have to add an instance for each. You may add some default behavior though, by restricting the type parameters of the class:{-# LANGUAGE DeriveFunctor #-}{-# LANGUAGE MultiParamTypeClasses #-}class Extract f where extract :: f a -> aclass (Extract f, Functor f, Num a) => Adjustable f a where adjust :: f a -> a adjust = extract . fmap (+20)data AdjusterType a = Adjuster a deriving (Functor)instance Extract AdjusterType where extract (Adjuster a) = ainstance Adjustable AdjusterType Int where-- don't have to write any code here 这篇关于可能“超载”通过FlexibleInstances返回不同的类型,或者匹配类型类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-31 08:55