Partially evaluated type in classes

天大地大妈咪最大 提交于 2020-02-24 11:13:41

问题


This is a concrete version of my question asked here. I have an algorithm that produces some output and can produce some auxiliary information, which I may or may not care about in a given case (I call this auxiliary information "annotation" below). I am using Euclid's algorithm for an illustration:

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

The function gcd a b returns an AnnotatedGcd which in the example could be GcdOnly which is just the gcd g, or it could be GcdWithSteps in addition counting how many steps it took, or it could be GcdExtended also providing coefficients k,l such that g = k * a + l * b:

*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)

Now what if I want to count the number of steps and get the coefficients? Rather than keeping writing more and more instances of AnnotatedGcd I would want to have the notion of an annotation and say that tuples of annotations are annotations again:

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)

This is valid Haskell code except for the last instance declaration. The question is: how could one actually make such a declaration?

The general version would be: given two parametric classes Class a and Class b how can one turn tuples (a,b) into instances of both classes (one with respect to the first parameter, one with respect to the second).

来源:https://stackoverflow.com/questions/60079676/partially-evaluated-type-in-classes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!