はい、限られた範囲で行うことができます。
しかし、まず必要になるのは
{-# LANGUAGE Rank2Types #-}
定義しましょう
data M a b = M { name :: Int -> String -> String, eval :: a -> b }
私はあなたの名前にもっと構造を追加しているので、より良いショーサポートを得ることができます. ;)
次に、クラスを定義しましょう。
class Magic m where
magic :: M a b -> m a b
instance Magic M where
magic = id
instance Magic (->) where
magic (M _ f) = f
ここで、次のタイプを検討してください。
type MyFunc a b = forall m. Magic m => m a b
の結果の型はまたは のmagic
いずれかです。(a -> b)
M a b
そのため、のメンバーとして使用できますMyFunc
。インスタンスをディスパッチできないため、このタイプはやや満足のいくものではありませんが、
inc :: MyFunc Int Int
inc = magic (M (const (showString "inc")) (+1))
test :: Int
test = inc 1
うまく動作します。
それらを表示するためのかなり良い方法を作ることさえできます。show on を使用することはできませんがMyFunc
、 に対して定義することはできますM
。
instance Show (M a b) where
showsPrec d (M s _) = s d
次に、 を取得するために適用できる関数M a b
(および拡張によって any MyFunc
) を作成できますM a b
。
m :: M a b -> M a b
m = id
MyFunc
そして、 sを表示する特別なコンビネータを定義できます。
showM :: MyFunc a b -> String
showM f = show (m f)
それから私たちは遊ぶことができます。s の合成を定義できますMyFunc
。
infixr 9 .#
(.#) :: MyFunc b c -> MyFunc a b -> MyFunc a c
f .# g = magic (M
(\d -> showParen (d > 9) $ showsPrec 10 (m f) .
showString " . " .
showsPrec 9 (m g))
(f . g))
inc2 :: MyFunc Int Int
inc2 = inc .# inc
test2 :: Int
test2 = inc2 1
bar, baz :: String
bar = showM inc
baz = showM inc2
また、名前に十分な構造を与えたので、より複雑な構成でも、不必要な括弧なしで正しい括弧を取得できます。
*Main> showM $ inc2 .# inc
"(inc . inc) . inc"
*Main> showM $ inc .# inc2
"inc . inc . inc"
ただし、 のインスタンスは定義できないことにMyFunc
注意しtype
てnewtype
ください。インスタンスを定義するには、それらを onM
で定義してから、 を使用m
してその型に変換し、暗黙的なディスパッチが取得する型を持つようにする必要があります。
ランク 2 のタイプであるため、これらをローカル コンテキストで頻繁に使用する場合は、NoMonoLocalBinds
および/またはをオンにすることもできますNoMonomorphismRestriction
。