首页 > 解决方案 > 类中的部分评估类型

问题描述

这是我在这里提出的问题的具体版本。我有一个算法可以产生一些输出并且可以产生一些辅助信息,在给定的情况下我可能关心也可能不关心(我在下面将此辅助信息称为“注释”)。我正在使用 Euclid 算法进行说明:

class AnnotatedGcd m where
    actually :: (Integral a) => a -> m a
    update :: (Integral a) => a -> m a -> m a

newtype GcdOnly a = Gcd a deriving Show

instance AnnotatedGcd GcdOnly where
    actually = Gcd
    update q = id

newtype GcdWithSteps a = GcdS (a, Int) deriving Show

instance AnnotatedGcd GcdWithSteps where
    actually x = GcdS (x, 0)
    update q (GcdS (x, s)) = GcdS (x, s+1)

newtype GcdExtended a = GcdE (a, a, a) deriving Show

instance AnnotatedGcd GcdExtended where
    actually x = GcdE (x, 1, 0)
    update q (GcdE (x, k, l)) = (GcdE (x, l, k - q*l))

gcd :: (Integral a, AnnotatedGcd m) => a -> a -> m a
gcd a b = if b == 0 then actually a else update q ((Main.gcd) b r)
  where q = a `div` b
        r = a `rem` b

该函数在示例中gcd a b返回一个which 可以是 gcd g,或者它可以另外计算它走了多少步,或者它还可以提供系数 k,l 使得 g = k * a + l *乙:AnnotatedGcdGcdOnlyGcdWithStepsGcdExtended

*Main> (Main.gcd 253 83) :: (GcdOnly Int)
Gcd 1
*Main> (Main.gcd 253 83) :: (GcdWithSteps Int)
GcdS (1,4)
*Main> (Main.gcd 253 83) :: (GcdExtended Int)
GcdE (1,21,-64)

现在如果我想计算步数获得系数怎么办?与其继续写越来越多的实例,不如说AnnotatedGcd我想要一个注释的概念,并说注释的元组又是注释:

class GcdAnnotation a where
    emptyAnnotation :: a
    annotate :: Integral b => b -> a -> a

instance (GcdAnnotation a, GcdAnnotation b) => GcdAnnotation (a,b) where
    emptyAnnotation = (emptyAnnotation, emptyAnnotation)
    annotate q (x, y) = (annotate q x, annotate q y)

instance (GcdAnnotation a, GcdAnnotation b, GcdAnnotation c) => GcdAnnotation (a,b,c) where
    emptyAnnotation = (emptyAnnotation, emptyAnnotation, emptyAnnotation)
    annotate q (x, y, z) = (annotate q x, annotate q y, annotate q z)

instance GcdAnnotation b => AnnotatedGcd (,b) where
    actually x = (x, emptyAnnotation)
    update q (g, x) = (g, annotate q x)

这是有效的 Haskell 代码,除了最后一个实例声明。问题是:一个人怎么能真正做出这样的声明?

一般版本是:给定两个参数类Class a,以及Class b如何将元组(a,b)转换为两个类的实例(一个关于第一个参数,一个关于第二个参数)。

标签: haskelltypes

解决方案


推荐阅读