更广泛的新型派生

当在特定的类上下文中使用时,Newtypes通常用于改变某些类型的行为。 例如,可以使用Data.Monoid.All包装来改变Bool在用作Monoid时的行为。

我目前正在撰写这样一种适用于大量不同类型的新型包装。 包装应该改变一个特定类实例的行为。 它可能看起来像这样:

newtype Wrapper a = Wrapper a

instance Special a => Special (Wrapper a) where
  -- ...

但是,添加这个包装器通常会改变包装类型的可用性。 例如,如果我以前能够使用函数mconcat :: Monoid a => [a] -> a ,我现在无法将它用于包装值的列表。

我当然可以使用-XGeneralizedNewtypeDeriving-XGeneralizedNewtypeDeriving newtype Wrapper a = Wrapper a deriving (Monoid) -XGeneralizedNewtypeDeriving newtype Wrapper a = Wrapper a deriving (Monoid) 。 但是,这只能解决Monoid和其他类的问题,而我将处理一个充满不同类的开放世界,而孤立的孤立泛型新类型派生并不是真正的实际选择。 理想情况下,我想写deriving hiding (Special) (派生每个类除Special之外),但这不是有效的Haskell,当然。

有没有这样做或我只是拧了,需要添加一个GHC功能请求?


看, GeneralizedNewtypeDeriving的新型GeneralizedNewtypeDeriving是不安全的。 就此而言,这是一种不安全的做法

{-# LANGUAGE GADTs, ConstraintKinds #-}
import Data.Monoid
import Unsafe.Coerce

data Dict c where
  Dict :: c => Dict c

newtype Wrapper a = Wrapper a

addDictWrapper :: Dict (f a) -> Dict (f (Wrapper a))
addDictWrapper = unsafeCoerce

你可以随时使用它,只要你需要typeclass实例

intWrapperNum :: Dict (Num (Wrapper Int))
intWrapperNum = addDictWrapper Dict

two :: Wrapper Int
two = case intWrapperNum of
           Dict -> 1 + 1

这个传递显式字典的系统非常普遍,并且有一个非常好的(尽管是实验性的)库来支持它,称为Data.Constraint


恐怕GHC中没有直接的方法。 但我认为你可以使用Template Haskell解决你的问题。

链接地址: http://www.djcxy.com/p/7533.html

上一篇: Even more generalized newtype deriving

下一篇: Is there a way to define an existentially quantified newtype in GHC Haskell?