evl*_*gii 0 haskell functional-programming
I was solving a super simple problem and came out with this code. I feel like there should be a way to eliminate arguments x and y in areaOrPerimeter. But I can't find a way to do it. Is it possible to get rid of them somehow? I have a strong feeling that it should be possible.
areaOrPerimeter :: Double -> Double -> Double
areaOrPerimeter x y
| x == y = area x y
| otherwise = perimeter x y
area :: Num a => a -> a -> a
area = (*)
perimeter :: Num a => a -> a -> a
perimeter x y = 2 * (x + y)
Run Code Online (Sandbox Code Playgroud)
如果您想有机会以一种不令人讨厌的方式做到这一点,您应该首先将参数有意义地组合在一起,以避免处理多个参数:
data RectangleSize a = RectangleSize {width, height :: a}
Run Code Online (Sandbox Code Playgroud)
然后我们可以使函数和x==y检查也更有意义:
area :: Num a => RectangleSize a -> a
area (RectangleSize w h) = w*h
perimeter :: Num a => RectangleSize a -> a
perimeter (RectangleSize w h) = 2*(w+h)
isSquare :: Eq a => RectangleSize a -> Bool
isSquare (RectangleSize w h) = w==h
Run Code Online (Sandbox Code Playgroud)
这给我们留下了已经更有希望的
areaOrPerimeter :: RectangleSize Double -> Double
areaOrPerimeter r
| isSquare r = area r
| otherwise = perimeter r
Run Code Online (Sandbox Code Playgroud)
为了让这一点成为免费,你仍然需要复制三遍r。这可以通过函数实例来完成(是否应该是另一回事) ,即可以写为. 在这种情况下,你想要做出决定,所以你需要一流的;通常是这样写的Applicative\x -> f x (g x)f<*>gif
if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y
Run Code Online (Sandbox Code Playgroud)
现在您可以isSquare通过组合升级到切换功能if':
if' . isSquare :: Eq a => RectangleSize a -> b -> b -> b
Run Code Online (Sandbox Code Playgroud)
现在我们可以使用 applicative 实例将矩形分配给所有组件:
areaOrPerimeter = if'.isSquare <*> area <*> perimeter
Run Code Online (Sandbox Code Playgroud)
在我看来,实际上并不算太破烂。