我想使用运算符和如下规则定义来构建规则:
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
实例类型类为Symbol
as的时候没问题
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] 删除。
我来说两句