我的第一个想法是写这样的东西
paste :: Region -> Image a -> Image a -> Image a
paste (Image bol) img1 img2 = if bol
then -- do the pasting
else -- well do nothing
但我不知道怎么做粘贴。有人能指出我正确的方向吗?
答案 0 :(得分:8)
虽然当你实际参加考试时这很有用,但这里是“教一个人拖网捕鱼”的答案:开始时没有定义任何结果,让编译器(必须GHC≥7.8)评论。请注意,存根是错误的:如果Image
只是type
- def,则不需要值构造函数Image
来对其进行模式匹配。
newtype Image a = Image (Position -> a)
-- it should be `newtype` instead of `type`, else there
-- won't be an explicit `Image` value constructor
type Position = (Float, Float)
type Region = Image Bool
paste :: Region -> Image a -> Image a -> Image a
paste (Image bol) img1 img2 = _
GHC将回来
/tmp/wtmpf-file6644.hs:8:31:
Found hole ‘_’ with type: Image a
Where: ‘a’ is a rigid type variable bound by
the type signature for
paste :: Region -> Image a -> Image a -> Image a
...
好的,这并不奇怪:我们已经知道结果应该是一张图片。现在,Image
只有一个构造函数,即Image
,所以我们确定需要构造这样的图像。仍然不了解内部实现:
paste (Image bol) img1 img2 = Image _
给出
/tmp/wtmpf-file6644.hs:8:37:
Found hole ‘_’ with type: Position -> a
Where: ‘a’ is a rigid type variable bound by
the type signature for
paste :: Region -> Image a -> Image a -> Image a
at /tmp/wtmpf-file6644.hs:7:10
啊哈,所以隐藏在Image
中的额外功能参数潜伏着!我们的模式也匹配:
paste (Image bol) img1 img2 = Image $ \pos -> _
/tmp/wtmpf-file6644.hs:8:47:
Found hole ‘_’ with type: a
...
好的,a
是完全不透明的,所以现在我们确定没有进一步的信息我们无法做什么。幸运的是,我们确实以参数的形式提供了进一步的信息。正如GHC将通知您:
...
Relevant bindings include
pos :: Position (bound at /tmp/wtmpf-file6644.hs:8:40)
img2 :: Image a (bound at /tmp/wtmpf-file6644.hs:8:24)
img1 :: Image a (bound at /tmp/wtmpf-file6644.hs:8:19)
bol :: Position -> Bool (bound at /tmp/wtmpf-file6644.hs:8:14)
我们可以使用很多 ...这很好,因为这很明显应该做什么:我们可以提供pos
作为bol
的论据。然后,结果会输入Bool
(与bol
本身不同),因此现在可以成为if
切换的合适人选。
paste (Image bol) img1 img2 = Image $ \pos -> if bol pos
then _
else _
...
Found hole ‘_’ with type: a
...
之前看过,所以我们需要更多的信息。让我们回顾一下这些论点:Image a
仍然可以模式匹配
paste (Image bol) (Image img1) (Image img2)
= Image $ \pos -> if bol pos
then _
else _
现在说:
Relevant bindings include
pos :: Position (bound at /tmp/wtmpf-file6644.hs:9:14)
img2 :: Position -> a (bound at /tmp/wtmpf-file6644.hs:8:39)
img1 :: Position -> a (bound at /tmp/wtmpf-file6644.hs:8:26)
bol :: Position -> Bool (bound at /tmp/wtmpf-file6644.hs:8:14)
啊哈,所以img1
和img2
可以根据需要提供a
值,我们只需要先提供Position
。好吧,我们仍然有pos
,所以很明显该做什么:
paste (Image bol) (Image img1) (Image img2)
= Image $ \pos -> if bol pos
then img1 pos
else img2 pos
...或交换两张图片(自己想一想)。但是,实际上并没有任何其他定义只能使用给定的信息(以及所有)来编写,所以这种类型的孔过程是实现函数的一种非常简单的方法。
答案 1 :(得分:1)
好的。您的屏幕坐标由[0,1]×[0,1]矩形表示。区域是该矩形的布尔函数,当且仅当坐标位于该区域时才返回true。然后你有两个图像,img1
和img2
,它们是从坐标到像素的映射(或理论上的映射)。
您想要为img1
或reg
以外的坐标img2
返回一个新图像,该图像等于reg
。图像是从坐标到像素的映射,因此您实际上正在返回一个函数。
类型为Region -> Image a -> Image a -> Image a
,但请记住Image a
为Position -> a
,而Region
为Image Bool
,所以这真的是(Position -> Bool) -> (Position -> a) -> (Position -> a ) -> Position -> a
。我们在Position
之前需要最后的-> a
参数,并将其作为三个函数参数的参数。
因此,
paste :: Region -> Image a -> Image a -> Image a
-- Is really: (Position->Bool) -> (Position->a) -> (Position->a) -> Position -> a
paste reg overlay bg coords | reg coords == True = overlay coords
| otherwise = bg coords
带有测试用例的较长版本:
module Image where
type Image a = Position -> a
type Position = (Float, Float) -- [0,1]×[0,1]
data Color = RGB Int Int Int -- Pixels have values in [0,255]×[0,255]×[0,255].
deriving Show
-- Not efficient for real-world use, but will do for now.
type Region = Image Bool
type ColorImage = Image Color
paste :: Region -> Image a -> Image a -> Image a
-- Is really: (Position->Bool) -> (Position->a) -> (Position->a) -> Position -> a
paste reg overlay bg coords | reg coords == True = overlay coords
| otherwise = bg coords
allRed :: ColorImage
allRed _ = RGB 255 0 0
allWhite :: ColorImage
allWhite _ = RGB 255 255 255
unitCircle :: Region
unitCircle (x,y) = sqrt (x'*x' + y'*y') <= 0.5
where x' = x - 0.5
y' = y - 0.5
redCircleOnWhite :: ColorImage
redCircleOnWhite = paste unitCircle allRed allWhite
您可以在REPL中测试redCircleOnWhite
。