甚至更广义的新型派生

dfl*_*str 9 haskell typeclass ghc newtype

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

我目前正在编写一个适用于各种不同类型的newtype包装器.包装器应该改变一个特定类实例的行为.它可能看起来像这样:

newtype Wrapper a = Wrapper a

instance Special a => Special (Wrapper a) where
  -- ...
Run Code Online (Sandbox Code Playgroud)

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

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

有没有办法做到这一点,或者我只是搞砸了,需要添加GHC功能请求?

Phi*_* JF 3

瞧,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
Run Code Online (Sandbox Code Playgroud)

然后您可以在需要类型类实例时随时使用它

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

two :: Wrapper Int
two = case intWrapperNum of
           Dict -> 1 + 1
Run Code Online (Sandbox Code Playgroud)

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