在Haskell中,在处理临时多态性(例如Monad and functor)时,有许多较高的多态性示例。但是,我想不出任何示例来参数多态性。
这是可能的,如果是这样,我可以有一个有用的例子吗?
如果您仍然允许打字机约束,则答案是, nure !例如。我仍然称
之类的东西normalise :: (Foldable f, Functor f, Fractional n) => f n -> f n
normalise v = fmap (/sum v) V
参数多态性。但是我想那不是你想到的。
显然可能的另一件事就是禁忌类型以具有特定表格_ _
,例如
hmap :: (f a -> f b) -> [f a] -> [f b]
hmap = map
这并不是很引人注目,但是在某些应用程序中可能是对Checker类型的微妙提示而有用的。实际上,这是您解决幻影参数问题的一种方法:而不是
class LengthyList l where minimumLength :: l a -> Int
instance LengthyList [] where minimumLength _ = 0
instance LengthyList NonEmpty where minimumLength _ = 1
您可能会签名
minimumLength :: p (l a) -> Int
又名
minimumLength :: proxy (l a) -> Int
因此,您仍然通过l
的类型信息,但保证实现无法在运行时评估参数。
但是,这样做的标准方法是
minimumLength :: Tagged (l a) Int
或
minimumLength :: Proxy (l a) -> Int
通常,f a
也无法使用fa
完成,因此,从本质上讲,您可以将任何此类高阶参数函数的类型重写为一阶参数上的多态性。
您完全可以做到这一点。类型的同义词猪工人喜欢:
type f ~> g = forall a . f a -> g a
由于我实际上不知道的原因,这代表了函子f
和g
之间的自然转换(到底是什么)。但是,一个函数可以对f ~> g
类型进行参数,并将其应用于所喜欢的多种类型f a
。使用非规范类型(特定于高阶嵌套数据类型,例如Ralf Hinze,例如在数值表示中探索的高阶嵌套数据类型),可以将其应用于无限数量的不同类型。
一个人为的例子:
{-# LANGUAGE RankNTypes, TypeOperators #-}
type f ~> g = forall a . f a -> g a
data Two g a = Two (g a) (g a)
data Foo f a = This (f a)
| That (Foo (Two f) a)
hello :: (f ~> g) -> Foo f a -> Foo g a
hello t (This fa) = This (t fa)
hello t (That buh) =
That (hello ((Two x y) -> Two (t x) (t y)) buh)
hello
在类型f
和g
中是多态性的,每个类型都有 * -> *
。†我相信将其转换为仅使用类型的*
可能需要非平凡的重构。
‡实际上,如果启用PolyKinds
,f
和g
将每个都有一个多型类型k -> *
。
我非常喜欢的一个示例是列表的foldr
操作员,该列表由其长度索引:它是acky Nat -> *
的谓词p
,并保证如果您将其应用于一个长度列表m
然后您获得了p m
的证明。
这对应于这种类型:
foldr :: forall a (p :: Nat -> *).
(forall n. a -> p n -> p ('Succ n)) ->
p 'Zero ->
forall n. Vec a n -> p n
这个额外的精确度使得实现例如append
使用foldr
,而不必通过模式匹配进行。
append :: forall a m n. Vec a m -> Vec a n -> Vec a (m :+: n)
我已经上传了一个完整的要点,所有正确的语言扩展已打开,并且代码与这些类型相对应,以防您要窥视。