gpt4 book ai didi

haskell - "overloading"能否通过 FlexibleInstances 返回不同的类型,或者匹配类型类?

转载 作者:行者123 更新时间:2023-12-01 23:22:19 24 4
gpt4 key购买 nike

我很好奇在 Haskell 的类型类中可以通过“FlexibleInstances”完成什么样的“重载”。

作为一个简单的测试,这里是一个 AdjusterType 数据类型的例子。它定义了一个 adjust 操作,该操作将根据它包含的是 Integer 还是 Double 来为其值添加不同的数量:

{-# LANGUAGE FlexibleInstances #-}

class Adjustable a where
adjust :: a -> Double

data AdjusterType a = Adjuster a
deriving Show

instance Adjustable (AdjusterType Integer) where
adjust (Adjuster a) = fromIntegral (a + 20)

instance Adjustable (AdjusterType Double) where
adjust (Adjuster a) = a + 0.04

正如预期的那样有效:

Prelude> adjust (Adjuster (1000 :: Integer))
1020.0

Prelude> adjust (Adjuster (3 :: Double))
3.04

是否可以让 adjust 的 Integer 版本返回 Integer,而 Double 版本返回 Double?

泛化 adjust 的签名并删除整数情况下的 fromIntegral 不起作用:

class Adjustable a where
adjust :: Num n => a -> n

instance Adjustable (AdjusterType Integer) where
adjust (Adjuster a) = a + 20

这会产生一个错误,指出“n”是一个与 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 -> n
Relevant bindings include
adjust :: AdjusterType Integer -> n
In the first argument of ‘(+)’, namely ‘a’
In the expression: a + 20

Integer 不匹配时它期望的是什么类型...或者没有类型实际工作并且它只是一个奇怪的错误消息? (n 是小写的,所以大概是知道它不是数据类型)

实例规范中的类型约束似乎也没有参与匹配解析:

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.04

所以它们就像重复项一样,就好像它们都是Adjustable (AdjusterType x))。约束仅在解析完成后适用。

有没有办法为类型类提供像上面那样的重载行为,或者它必须始终针对特定实例?

最佳答案

Is it possible to make the Integer version of adjust return an Integer, and the Double version return a Double?

您可以使 Adjustable 类型类接受两个类型参数而不是一个,这样它就会知道 AdjusterType 中的内容:

{-# LANGUAGE MultiParamTypeClasses #-}

class Adjustable f a where
adjust :: f a -> a

那么实例应该是:

instance Adjustable AdjusterType Int where
adjust (Adjuster a) = a + 20

instance Adjustable AdjusterType Double where
adjust (Adjuster a) = a + 0.04

以及 ghci 的一些结果:

> :set +t

> adjust (Adjuster (100 :: Int))
< 120
< it :: Int
> adjust (Adjuster (100 :: Double))
< 100.04
< it :: Double

What type was it expecting here that Integer isn't matching...or would no type actually work and it's just a weird error message?

adjust 的返回类型是 forall n 类型。 Num n => n,一种具有单一约束 Num 的多态类型,因此返回具体类型的函数不会进行类型检查。用 fromIntegral 包装你的函数将解决问题,因为 fromIntegral::(Integral a, Num b) => a -> b

Is there any way to provide an overloaded behavior like above to a type class, or must it always be to a specific instance?

如果您希望该函数对每种不同的类型都有不同的行为,是的,您必须为每种类型添加一个实例。不过,您可以通过限制类的类型参数来添加一些默认行为:

{-# LANGUAGE DeriveFunctor         #-}
{-# LANGUAGE MultiParamTypeClasses #-}

class Extract f where
extract :: f a -> a

class (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) = a

instance Adjustable AdjusterType Int where
-- don't have to write any code here

关于haskell - "overloading"能否通过 FlexibleInstances 返回不同的类型,或者匹配类型类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35745191/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com