繁体   English   中英

存在类型的多态函数

[英]polymorphic function on existential type

所以说我有一节课:

class C a where
  reduce :: a -> Int

现在我想将其打包成数据类型:

data Signal = forall a. (C a) => Signal [(Double, a)]

由于存在量化,我可以在信号上调用C方法,但信号不公开类型参数:

reduceSig :: Signal -> [(Double, Int)]
reduceSig (Signal sig) = map (second reduce) sig

现在因为C有很多方法,我自然而然的下一步就是拉出'reduce'函数,这样我就可以替换任何方法:

mapsig :: (C a) => (a -> a) -> Signal -> Signal
mapsig f (Signal sig) = Signal (map (second f) sig)

输入错误! 无法推断(a1~a)。 进一步思考,我认为它的含义是'f'是某个C实例的函数,但我无法保证它与信号中的C实例相同 ,因为类型参数是隐藏的! 我想要它,我明白了。

那么这是否意味着不可能推广reduceSig? 我可以忍受这个,但我已经习惯于在haskell中自由地分解函数了,不得不编写样板文件感觉很奇怪。 另一方面,我想不出任何方式来表示一个类型等于Signal内部的类型,而不是给Signal一个类型参数。

你需要表达什么是f ,像reduce在使用reduceSig ,可以适用于任何类型的实例C ,而不是目前的类型,其中f工作在一个单一的类型,它是实例C 这可以这样做:

mapsig :: (forall a. (C a) => a -> a) -> Signal -> Signal
mapsig f (Signal sig) = Signal (map (second f) sig)

您需要使用RankNTypes扩展名,就像使用存在类型时一样; 请注意, mapsig实现是相同的,该类型刚刚被推广。

基本上,这种类型的, mapsig得到决定哪一个函数被调用上; 使用您之前的类型, mapsig调用者可以决定哪个不起作用,因为只有mapsig知道正确的a ,即Signal内的一个。

但是, mapsig reduce不起作用,原因很简单: reduce :: (C a) => a -> Int ,你不知道a是Int! 您需要为mapsig提供更通用的类型(具有相同的实现):

mapsig :: (C b) => (forall a. (C a) => a -> b) -> Signal -> Signal

即, f是一个函数,它采用任何类型的C实例,并生成一个类型为C的实例(该类型在mapsig调用时被固定mapsig调用者选择;即,值为mapsig f可以在任何信号被调用,它总是会产生一个信号以相同的一个结果(这并不是说,你可以从外部检查此)。)

Existentials和rank-N类型确实很棘手,所以这可能需要一些时间来消化。 :)


作为附录,值得指出的是,如果C所有函数看起来像a -> r r,那么你最好创建一个记录 ,即转向

class C a where
  reduce :: a -> Int
  foo :: a -> (String, Double)
  bar :: a -> ByteString -> Magic

data Signal = forall a. (C a) => Signal [(Double, a)]

mapsig :: (C b) => (forall a. (C a) => a -> b) -> Signal -> Signal

data C = C
  { reduce :: Int
  , foo :: (String, Double)
  , bar :: ByteString -> Magic
  }

data Signal = Signal [(Double, C)]

mapsig :: (C -> C) -> Signal -> Signal

这两种信号类型实际上是等价的! 前一种解决方案的好处只有在您有其他使用C数据类型时才会出现, 而不会对其进行存储量化,因此您可以拥有使用特定知识和特定C实例操作的代码。 如果您这个类的主要用例是通过存在量化,那么您可能首先不需要它。 但我不知道你的程序是什么样的:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM