首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过FlexibleInstances“重载”可以返回不同的类型,或者匹配类型吗?

通过FlexibleInstances“重载”可以返回不同的类型,或者匹配类型吗?
EN

Stack Overflow用户
提问于 2016-03-02 10:55:56
回答 2查看 106关注 0票数 3

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

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

代码语言:javascript
复制
{-# 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

这方面的工作与预期一样:

代码语言:javascript
复制
Prelude> adjust (Adjuster (1000 :: Integer))
1020.0

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

adjust 的的整数版本有可能返回整数,而双版本返回双?吗?

概括adjust的签名和删除整数情况下的fromIntegral不起作用:

代码语言:javascript
复制
class Adjustable a where
    adjust :: Num n => a -> n

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

这会产生一个错误,说明"n“是一个不匹配Integer的刚性类型变量:

代码语言:javascript
复制
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不是matching...or,它实际上不会工作,而它只是一条奇怪的错误消息? (n是小写的,所以它可能知道它不是数据类型)

实例规范中的类型约束似乎也不参与匹配的解决方案:

代码语言:javascript
复制
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))一样。该约束仅在决议完成后才适用。

是否有向类型类提供像上面这样的重载行为的方法,或者必须始终将其提供给特定实例?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-02 12:01:38

是否可以使整定版本的调整返回一个整数,而双版本返回一个双?

您可以让Adjustable类型类接受两个类型参数而不是一个类型参数,这样它就可以知道AdjusterType内部是什么

代码语言:javascript
复制
{-# LANGUAGE MultiParamTypeClasses #-}

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

那么这些实例应该是:

代码语言:javascript
复制
instance Adjustable AdjusterType Int where
    adjust (Adjuster a) = a + 20

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

而ghci的一些结果是:

代码语言:javascript
复制
> :set +t

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

在这里,期望Integer不是matching...or的类型是什么类型的,它实际上不会工作,它只是一条奇怪的错误消息?

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

是否有任何方法向类型类提供像上面这样的重载行为,或者必须始终将其提供给特定实例?

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

代码语言:javascript
复制
{-# 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
票数 3
EN

Stack Overflow用户

发布于 2016-03-02 20:46:40

使用类型族(特别是关联数据类型)的解决方案如下:

代码语言:javascript
复制
{-# LANGUAGE TypeFamilies, FlexibleInstances #-}

class Adjustable a where
    type Elem a :: *
    adjust :: a -> Elem a


data AdjusterType a = Adjuster a
    deriving (Show)


instance Adjustable (AdjusterType Integer) where
    type Elem (AdjusterType Integer) = Integer

    adjust (Adjuster a) = a + 20

instance Adjustable (AdjusterType Double) where
    type Elem (AdjusterType Double) = Double

    adjust (Adjuster a) = a + 0.04

main = do
    let x = Adjuster 1 :: AdjusterType Integer
        y = Adjuster 1 :: AdjusterType Double
    print $ adjust x
    print $ adjust y

它编译并输出如下:

代码语言:javascript
复制
21
1.04
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35745191

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档