用于编写破坏性运算符的更好界面,第二部分
请参阅我之前关于编写 opencv 运算符的问题,以了解正在发生的情况。
我想出了一个新的接口,它允许以一种可组合的方式组合破坏性的二元运算:
newtype IOP a b = IOP (a -> IO b)
instance Category IOP where
id = IOP return
(IOP f) . (IOP g) = IOP $ g >=> f
(&#&) :: IOP (Image c d) e -> IOP (Image c d) f
-> IOP (Image c d) (Image c d,Image c d)
(IOP f) &#& (IOP g) = IOP $ op
where
op i = withClone i $ \cl -> (f i >> g cl >> return (i,cl))
runIOP (IOP f) img = withClone img f
有了这个,我可以轻松地表达“减去高斯运算符”:
subtract :: IOP (Image c d, Image c1 d1) (Image c d)
mulScalar :: d -> IOP (Image c d) (Image c d)
subtractScalar :: d -> IOP (Image c d) (Image c d)
gaussian :: (Int, Int) -> IOP (Image GrayScale D32) (Image GrayScale D32)
(gaussian (11,11) &#& id) >>> subtract >>> mulScalar 5
对我来说,这似乎是一个相当安全的替代方案,尽管它在从某种意义上说,如果减去后的某些操作需要这样做,它可能也可以重新使用克隆的图像。但它似乎仍然是完全纯净且未优化版本的可接受的替代方案:
mulScalar 5 $ gaussian (11,11) img `subtract` img
-- Or with nicer names for the operators
5 * gaussian (11,11) img - img
问题
- 首先,这是一个合理的结构吗?
- 是否有理由更喜欢上一个问题中的结构?
- 您如何扩展它来实现“找到图像中的最小值,从图像中减去它,然后将图像与其范围相乘(即最大值-最小值)”的操作。
- 我应该将这些问题分成多个问题吗?
See my earlier question about composing opencv operators for an explanation of what is going on.
I thought up a new interface that allows to compose destructive binary operations in a kind of composable way:
newtype IOP a b = IOP (a -> IO b)
instance Category IOP where
id = IOP return
(IOP f) . (IOP g) = IOP $ g >=> f
(&) :: IOP (Image c d) e -> IOP (Image c d) f
-> IOP (Image c d) (Image c d,Image c d)
(IOP f) & (IOP g) = IOP $ op
where
op i = withClone i $ \cl -> (f i >> g cl >> return (i,cl))
runIOP (IOP f) img = withClone img f
With this I can easily express the 'subtract the gaussian operator':
subtract :: IOP (Image c d, Image c1 d1) (Image c d)
mulScalar :: d -> IOP (Image c d) (Image c d)
subtractScalar :: d -> IOP (Image c d) (Image c d)
gaussian :: (Int, Int) -> IOP (Image GrayScale D32) (Image GrayScale D32)
(gaussian (11,11) & id) >>> subtract >>> mulScalar 5
To me this seems like a quite safe alternative, though it is not optimal in the sense, that it probably could re-use also the cloned image if some operation after subtract would require this. But it still seems like an acceptable alternative to the completely pure and unoptimized version:
mulScalar 5 $ gaussian (11,11) img `subtract` img
-- Or with nicer names for the operators
5 * gaussian (11,11) img - img
Questions
- Is this a reasonable structure in the first place?
- Is there a reason to prefer the structure in the previous question?
- How would you extend this to implement an operation 'find the minimum value in the image, subtract it from the image and then multiply the image with its range (i.e max-min).'
- Should I split these into multiple questions instead?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
继续哈马尔的评论,您可以从使用 kleisli 组合开始,完全避免 IOP。为了清楚起见,我将 ImageOp 作为类型同义词。另外,我将它专门化为始终返回单位,并相应地更改了一些其他类型签名,以便我们在变异函数(返回单位)和克隆函数(返回新值)以及函数
apOp 应用变异函数并返回变异值,以便我们可以轻松链接变异。
编辑
如果您愿意,可以如下整齐地编写
&#&
:我认为,这是这种风格非常具有表现力的一个很好的论据。
Continuing from hammar's comment, you can just use kleisli composition to begin with, avoiding the IOP altogether. I've kept ImageOp as a type synonym for clarity's sake. Also, I specialized it to always return unit, and changed some other type signatures accordingly so that we have a typed difference between mutating functions (returning unit) and cloining functions (returning a new value), and a function
apOp
that applies a mutating function and returns the mutated value so that we can chain mutations easily.Edit
If you feel like it, you can write
&#&
neatly as follows:Which, I think, is a good argument for this style being pretty expressive.