Eva*_*rge 14 haskell existential-type
所以说我有一节课:
class C a where
reduce :: a -> Int
Run Code Online (Sandbox Code Playgroud)
现在我想将其打包成数据类型:
data Signal = forall a. (C a) => Signal [(Double, a)]
Run Code Online (Sandbox Code Playgroud)
由于存在量化,我可以在信号上调用C方法,但信号不公开类型参数:
reduceSig :: Signal -> [(Double, Int)]
reduceSig (Signal sig) = map (second reduce) sig
Run Code Online (Sandbox Code Playgroud)
现在因为C有很多方法,我自然而然的下一步就是拉出'reduce'函数,这样我就可以替换任何方法:
mapsig :: (C a) => (a -> a) -> Signal -> Signal
mapsig f (Signal sig) = Signal (map (second f) sig)
Run Code Online (Sandbox Code Playgroud)
输入错误!无法推断(a1~a).进一步思考,我认为它的含义是'f'是某个C实例的函数,但我无法保证它与信号中的C实例相同,因为类型参数是隐藏的!我想要它,我明白了.
那么这是否意味着不可能推广reduceSig?我可以忍受这个,但我已经习惯于在haskell中自由地分解函数了,不得不编写样板文件感觉很奇怪.另一方面,我想不出任何方式来表达一个类型等于Signal内部的类型,而不是给Signal一个类型参数.
ehi*_*ird 18
你需要表达的是f,就像reduce在中使用的那样reduceSig,它可以应用于任何类型的实例C,而不是当前类型,它f适用于作为实例的单个类型C.这可以这样做:
mapsig :: (forall a. (C a) => a -> a) -> Signal -> Signal
mapsig f (Signal sig) = Signal (map (second f) sig)
Run Code Online (Sandbox Code Playgroud)
你需要RankNTypes扩展名,正如你在使用存在类型时经常做的那样; 注意,执行的mapsig是一样的,类型刚刚被一概而论.
基本上,这种类型的,mapsig获取决定哪个一个函数被调用上; 与以前的类型,呼叫者的mapsig到达决定,这是不行的,因为只有mapsig知道正确的一个,即内部的一个Signal.
但是,mapsig reduce不起作用,原因很明显reduce :: (C a) => a -> Int,而且你不知道那是一个 Int!您需要提供mapsig更通用的类型(具有相同的实现):
mapsig :: (C b) => (forall a. (C a) => a -> b) -> Signal -> Signal
Run Code Online (Sandbox Code Playgroud)
即,f是一个函数,它采用任何类型的实例C,并生成一个类型的实例C(该类型在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
Run Code Online (Sandbox Code Playgroud)
成
data C = C
{ reduce :: Int
, foo :: (String, Double)
, bar :: ByteString -> Magic
}
data Signal = Signal [(Double, C)]
mapsig :: (C -> C) -> Signal -> Signal
Run Code Online (Sandbox Code Playgroud)
这两种信号类型实际上是等价的!前一种解决方案的好处只有在您使用其他数据类型C 而不进行存在量化时才会出现,这样您就可以拥有使用特定实例的特殊知识和操作的代码C.如果您这个类的主要用例是通过存在量化,那么您可能首先不需要它.但我不知道你的程序是什么样的:)
| 归档时间: |
|
| 查看次数: |
788 次 |
| 最近记录: |