9

ニュータイプは、特定のクラス コンテキストで使用されたときに、特定の型の動作を変更するためによく使用されます。たとえば、Data.Monoid.AllラッパーをBool使用して、 として使用した場合の動作を変更しMonoidます。

私は現在、さまざまなタイプの広い範囲に適用されるような newtype ラッパーを作成しています。ラッパーは、1 つの特定のクラス インスタンスの動作を変更することになっています。次のようになります。

newtype Wrapper a = Wrapper a

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

ただし、このラッパーを追加すると、ラップされた型の使いやすさが変わることがよくあります。たとえば、以前は function を使用できた場合、mconcat :: Monoid a => [a] -> aラップされた値のリストには使用できなくなりました。

-XGeneralizedNewtypeDerivingもちろんとも使えますnewtype Wrapper a = Wrapper a deriving (Monoid)。ただし、これは問題を解決するだけでMonoid他のクラスは解決しませんが、さまざまなクラスでいっぱいのオープンワールドを扱うことになり、スタンドアロンの孤立した一般化された newtype の派生は実際には実用的なオプションではありません。deriving hiding (Special)理想的には、 ( を除くすべてのクラスを派生させて)書きたいSpecialのですが、もちろん、それは有効な Haskell ではありません。

これを行う方法はありますか、それとも単に失敗してGHC機能リクエストを追加する必要があるのでしょうか?

4

2 に答える 2

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

型クラスのインスタンスが必要なときはいつでも使用できます

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

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

明示的な辞書を渡すこのシステムは非常に一般的であり、Data.Constraintと呼ばれる非常に優れた (実験的ではありますが) それをサポートするライブラリがあります。

于 2012-10-01T03:32:13.137 に答える
0

GHCでそれを行う直接的な方法はないのではないかと思います。しかし、 TemplateHaskellを使用して問題を解決できると思います。

于 2012-10-01T06:46:07.733 に答える