是的,它可以在一定程度上完成。
但首先我们需要
{-# 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
的作品就好了。
我们甚至可以制作一个相当不错的方式来展示它们。尽管我们无法使用MyFunc
上的节目,但我们可以将它定义为M
。
instance Show (M a b) where
showsPrec d (M s _) = s d
然后我们就可以使我们能够适用于M a b
(通过扩展任何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)
然后我们就可以玩了。我们可以定义组成MyFunc
s。
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
。为了定义实例,您必须在M
上定义它们,然后使用m
转换为该类型,以便隐式调度具有要抓取的类型。
由于排名第二的类型,如果您在本地环境中大量使用它们,您可能还需要打开NoMonoLocalBinds
和/或NoMonomorphismRestriction
。
这是一种可怕的。我喜欢它。 –