Haskell 推导这个无点代码的步骤是什么?
我在查看一些代码时发现了以下gem,我敢打赌它是Haskell 推导这个无点代码的步骤是什么?,haskell,pointfree,lifting,Haskell,Pointfree,Lifting,我在查看一些代码时发现了以下gem,我敢打赌它是pointfreeoutput的复制粘贴: (我认为对于这个特殊的问题,以下内容比通常的foo/bar更合适:p) 有人能解释一下简化的步骤吗?(i)坐标b=(xb,yb)(ii)坐标=liftM2(,)xy尤其是,我对liftM2的用法有点困惑,因为我甚至没有意识到背景中隐藏着一个单子 我知道(I)也可以表示为:坐标s=(,)(xs)(yss),但我不确定在哪里/如何继续 另外,以下是我怀疑它来自pointfree(输出来自GHCI,:pl别名
pointfree
output的复制粘贴:
(我认为对于这个特殊的问题,以下内容比通常的foo
/bar
更合适:p)
有人能解释一下简化的步骤吗?(i)
坐标b=(xb,yb)
(ii)
坐标=liftM2(,)xy
尤其是,我对
liftM2
的用法有点困惑,因为我甚至没有意识到背景中隐藏着一个单子
我知道(I)也可以表示为:坐标s=(,)(xs)(yss)
,但我不确定在哪里/如何继续
另外,以下是我怀疑它来自
pointfree
(输出来自GHCI
,:pl
别名为pointfree
):
monad
liftM2
正在这里工作,这里是monad(>)a
函数。这相当于读取器
monad,正如您以前可能看到的那样
回想一下liftM2
的定义:
liftM2 :: Monad m => (a -> b -> r) -> m a -> m b -> m r
liftM2 f ma mb = do
a <- ma
b <- mb
return $ f a b
liftM2 :: (a -> b -> c) -> m a -> m b -> m c
liftM2 :: (a -> b -> c) -> (r -> a) -> (r -> b) -> (r -> c)
由于x,y::战列舰->Int
相当于(->)战列舰)Int
,那么m~(>)战列舰
。函数monad定义为
instance Monad ((->) a) where
return x = const x
m >>= f = \a -> f (m a) a
从本质上讲,monad函数允许您从多个函数中提取输出,前提是它们都具有相同的输入。一个更清楚的例子可能是
test = do
a <- (^2)
b <- (^3)
c <- (^4)
d <- show
return (a, b, c, d)
> test 2
(4, 8, 16, "2")
test=do
a这利用了(>)r
的Monad
实例,也称为“reader Monad”。这是从特定类型到a
的函数单子。(首先看看它为什么存在的动机。)
要查看它如何用于各种功能,请在ma
中将m
替换为(r->
。例如,如果我们只执行liftM
,我们会得到:
liftM :: (a -> b) -> (m a -> m b)
liftM :: (a -> b) -> ((r -> a) -> (r -> b))
:: (a -> b) -> (r -> a) -> (r -> b) -- simplify parentheses
…这只是函数合成。很好
对于liftM2
,我们可以做同样的事情:
liftM2 :: Monad m => (a -> b -> r) -> m a -> m b -> m r
liftM2 f ma mb = do
a <- ma
b <- mb
return $ f a b
liftM2 :: (a -> b -> c) -> m a -> m b -> m c
liftM2 :: (a -> b -> c) -> (r -> a) -> (r -> b) -> (r -> c)
所以我们看到的是一种将两个单参数函数与一个双参数函数组合的方法。这是一种将普通函数组合推广到多个参数的方法。其思想是我们创建一个函数,通过将单个r
传递给两个单参数函数,使两个参数传递到双参数函数。因此,如果我们有f::(r->a)
,g:(r->b)
和h:(a->b->c)
,我们产生:
\ r -> h (f r) (h r)
现在,这如何应用于您的代码?(,)
是双参数函数,x
和y
是Battleship->Int
类型的单参数函数(因为字段访问器就是这样工作的)。请记住:
liftM2 (,) x y = \ r -> (,) (x r) (y r)
= \ r -> (x r, y r)
一旦你内化了这样的多函数组合思想,像这样的无点代码就变得更具可读性了,不需要使用无点工具!在这种情况下,我认为非无点版本更好,但无点版本本身并不可怕。你可以很容易地重写
data Battleship = Battleship { x :: Int
, y :: Int
} deriving Show
placeBattleship :: Int -> Int -> Battleship
placeBattleship x y = Battleship x y
coordinates :: Battleship -> (Int, Int)
coordinates (Battleship x y) = (x, y)
这不是无点风格,但相当简单
data Battleship = Battleship { x :: Int
, y :: Int
} deriving Show
placeBattleship :: Int -> Int -> Battleship
placeBattleship x y = Battleship x y
coordinates :: Battleship -> (Int, Int)
coordinates (Battleship x y) = (x, y)