Haskell 不带函子的应用程序
我有一个类型Haskell 不带函子的应用程序,haskell,functor,ffi,applicative,Haskell,Functor,Ffi,Applicative,我有一个类型Image,它基本上是一个浮点数的c数组。创建函数很容易 例如map::(Float->Float)->Image->Image,或者zipWith:(Float->Float->Float)->Image->Image 然而,我觉得在这些函数之上还可以提供类似于应用程序实例的东西,允许更灵活的像素级操作,如(+)image1 image2)或(\x y z->(x+y)/z)i1 i2 i3)。然而,这种简单的方法失败了,因为图像类型不能包含浮点以外的内容,因此无法实现fmap 这
Image
,它基本上是一个浮点数的c数组。创建函数很容易
例如map::(Float->Float)->Image->Image
,或者zipWith:(Float->Float->Float)->Image->Image
然而,我觉得在这些函数之上还可以提供类似于应用程序实例的东西,允许更灵活的像素级操作,如(+)image1 image2)
或(\x y z->(x+y)/z)i1 i2 i3)
。然而,这种简单的方法失败了,因为图像类型不能包含浮点以外的内容,因此无法实现fmap
这是如何实现的?阅读评论,我有点担心这里的规模太小了。尺寸不匹配时是否存在合理的行为 同时,你也可以按照以下思路明智地做一些事情。即使您的数组不容易实现多态性,您也可以像这样创建一个
应用程序的
实例
data ArrayLike x = MkAL {sizeOf :: Int, eltOf :: Int -> x}
instance Applicative ArrayLike where
pure x = MkAL maxBound (pure x)
MkAL i f <*> MkAL j g = MkAL (min i j) (f <*> g)
alIm $ (f <$> imAL a1 <*> ... <*> imAL an)
通过投影和制表?如果是这样,您可以这样编写代码
data ArrayLike x = MkAL {sizeOf :: Int, eltOf :: Int -> x}
instance Applicative ArrayLike where
pure x = MkAL maxBound (pure x)
MkAL i f <*> MkAL j g = MkAL (min i j) (f <*> g)
alIm $ (f <$> imAL a1 <*> ... <*> imAL an)
这是typeclass编程的标准练习!(询问是否需要更多提示。)
然而,关键的一点是,包装策略意味着您不需要为了将功能超结构放在顶部而对数组结构进行调整。您希望如何对图像中的像素执行操作?也就是说,对于
(+)image1 image2)
,您是希望执行Haskell中的所有操作并构造新的结果图像,还是必须调用C函数来执行所有处理
如果是前者,养猪工人的答案是我会采取的方法
如果需要通过C处理所有图像操作,那么创建一个小DSL来表示操作如何?如果您将“像素”类型从
浮点扩展到无限连续域,您将得到一个更具组合性的图像类型。
作为这些概括的演示,请参阅本文和相应的图库(的有限样本)。
结果,您得到了Monoid
、Functor
、Applicative
、Monad
和Comonad
的实例。
此外,这些实例的意义完全由函数的相应实例决定,满足本文所述的语义类型类态射原则。
该论文的第13.2节简要介绍了图像。为什么不允许图像包含浮动以外的内容?当然,您的display::Image Float->IO()
只能使用浮点数拍摄图像,但对于其他函数,如map
则无所谓。图像类型是一个c数组,需要传递给c函数,而无需花费太多时间进行转换。另外,我假设,如果它可以保存函数之类的东西,那么在调用pure
之后,有几百万个部分求值的函数在性能上是相当糟糕的。(通过函数图像实现pure
也是有问题的,因为它无法知道图像的大小。)您可以定义您的类型,如type Image=CArray Float
并为CArray创建一个Functor实例,其中fmap是您的映射函数,并且您可以确保除了CArray Float之外,您不能进行任何CArray操作吗(例如,不要导出构造函数)您可能希望从抽象的图像
类型进行设计,而不是从其具体的内存表示进行设计。例如,在美国堪萨斯州的Conal Elliott的Pan和黑板中,遮罩表示为图像布尔
一个确定像素是否在遮罩内的函数。图像RGB
是一个图像可以渲染为位图的f RGB值。如果你需要这些不同类型的图像,你将需要一个更通用的表示。图像将主要由C操作。我想要的是一种在haskell中进行简单像素级操作的方法-为了添加像atan2这样的简单函数,一路拖到C是令人厌烦的。太好了!漂亮的much正是我想要的。我自己也不明白为什么我没有看到它。你是说为N个不同的arity函数创建N个实例,还是说typeclass注释更聪明的东西?你应该只需要两个实例:arity 0的基本情况(或者如果需要一个数组输入来限制输出的大小,则为1),还有一个步骤。等一下(抱歉,代码在注释中很糟糕)…classnary-ff-fi | ff->fi,fi->ff其中{naryHelp::(ArrayLike(Float->ff))->(Image->fi);NAry:(Float->ff)->(Image->fi);NAry=naryHelp.pure};实例NAry-Float-Image其中{naryHelp fi=alIm$f imAL i};实例NAry-ff-fi=>NAry(Float->ff)(Image->fi)其中{naryHelp fi=naryHelp(fimal i)}
只是一个额外的想法:ArrayLike
基本上很像repa延迟数组,对吧?至少我可以很容易地在alIm
中插入并行计算,并将force
定义为imAl.alIm
。我不知道repa的细节,但听起来很像我们来自same place(APL)。我相信他们比我考虑得更多。但是,是的,alIm
的实现是您分配劳动力的机会,imAL.alIm
用实际数组的投影替换任何旧的数组计算。