如何使用类型同义词重载运算符?

乔乔伊

我想使用运算符和如下规则定义来构建规则:

type Rule a = [Symbol a]

并且符号的定义为:

data Symbol a = Empty | End | LangSym a

现在定义一个<.>可以应用于以下四种情况的运算符

(<.>)::Symbol a->Symbol a->Rule a
(<.>)::Rule a->Symbol a->Rule a
(<.>)::Symbol a->Rule a->Rule a
(<.>)::Rule a->Rule a->Rule a

显然,我们需要<.>使用typeclass重载运算符

class RuleOperator s1 s2 where
    (<.>)::s1 a->s2 a->Rule a

实例类型类为Symbolas的时候没问题

instance RuleOperator Symbol Symbol where
    x <.> y = [x, y]

但是当实例具有时Rule a,由于的Rule a类型是同义词,我们不能那样做

instance RuleOperator Symbol Rule where
    ....

限制是我们不能将的定义更改Rule a

newtype Rule a = R [Symbol a]

由于其他模块依赖于的原始定义Rule a

有什么建议可以在不更改Rule定义的情况下实现带有重载的此类运算符

开支

如果您不想使用新类型包装器,则可以为此使用类型系列:

{-# LANGUAGE TypeFamilies, FlexibleInstances, MultiParamTypeClasses #-}

type Rule a = [Symbol a]

data Symbol a = Empty | End | LangSym a

class RuleOperator t1 t2 where
   type Elem t1 t2
   (<.>) :: t1 -> t2 -> Rule (Elem t1 t2)

instance RuleOperator (Symbol a) (Symbol a) where
   type Elem (Symbol a) (Symbol a) = a
   s1 <.> s2 = [s1, s2]

instance RuleOperator (Symbol a) (Rule a) where
   type Elem (Symbol a) (Rule a) = a
   (<.>) = (:)

instance RuleOperator (Rule a) (Symbol a) where
   type Elem (Rule a) (Symbol a) = a
   r <.> s = r ++ [s]

instance RuleOperator (Rule a) (Rule a) where
   type Elem (Rule a) (Rule a) = a
   (<.>) = (++)

使类采用完全应用的类型,以使类型同义词不再成为问题,然后使用Elem类型族恢复a参数。


这是两个允许由内而外和由外而内的类型推断的替代方法。一种使用类型族和约束:

{-# LANGUAGE TypeFamilies, FlexibleInstances, MultiParamTypeClasses #-}

type Rule a = [Symbol a]

data Symbol a = Empty | End | LangSym a

class (a ~ Elem t1 t2) => RuleOperator t1 t2 a where
   type Elem t1 t2
   (<.>) :: t1 -> t2 -> Rule (Elem t1 t2)

instance (a ~ b, a ~ c) => RuleOperator (Symbol a) (Symbol b) c where
   type Elem (Symbol a) (Symbol b) = a
   s1 <.> s2 = [s1, s2]

instance (a ~ b, a ~ c) => RuleOperator (Symbol a) (Rule b) c where
   type Elem (Symbol a) (Rule b) = a
   (<.>) = (:)

instance (a ~ b, a ~ c) => RuleOperator (Rule a) (Symbol b) c where
   type Elem (Rule a) (Symbol b) = a
   r <.> s = r ++ [s]

instance (a ~ b, a ~ c) => RuleOperator (Rule a) (Rule b) c where
   type Elem (Rule a) (Rule b) = a
   (<.>) = (++)

另一个使用函数依赖项(其作用有点像带约束的类型函数/族):

{-# LANGUAGE FunctionalDependencies, FlexibleInstances, MultiParamTypeClasses #-}

type Rule a = [Symbol a]
data Symbol a = Empty | End | LangSym a

class RuleOperator t1 t2 a | t1 -> a, t2 -> a where
  (<.>) :: t1 -> t2 -> Rule a
instance RuleOperator (Symbol a) (Symbol a) a where
   s1 <.> s2 = [s1, s2]
instance RuleOperator (Rule a) (Symbol a) a where
   r <.> s = r ++ [s]
instance RuleOperator (Symbol a) (Rule a) a where
  (<.>) = (:)
instance RuleOperator (Rule a) (Rule a) a where
  (<.>) = (++)

推理的一些测试:

sym1, sym2 :: Symbol Int
sym1 = undefined
sym2 = undefined

rule :: Rule Int
rule = undefined

testInsideOut = sym1 <.> rule  -- type is inferred

polySym :: Show a => Symbol a
polySym = Empty

polyRule :: Show a => Rule a
polyRule = [Empty]

testOutSideIn :: Rule Int
testOutSideIn = polySym <.> polyRule  -- Show instances are resolved to Int

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章