我查看了一些代码,并发现了以下gem,我敢打赌它是pointfree输出的复制粘贴:
(我认为下面这个问题比通常的foo/bar更合适:P)
import Control.Monad (liftM2)
data Battleship = Battleship { x :: Int
, y :: Int
} deriving Show
placeBattleship :: Int -> Int -> Battleship
placeBattleship x' y' = Battleship { x = x', y = y' }
coordinates :: Battleship -> (Int, Int)
coordinates = liftM2 (,) x y是否有人能解释一下需要简化的步骤:
(i) coordinates b = (x b, y b)
至:
(ii) coordinates = liftM2 (,) x y?
特别是,我对liftM2的使用感到有点困惑,因为我甚至没有意识到后台隐藏着一个单播。
我知道(i)也可以表示为:coordinates s = (,) (x s) (y s),但我不知道在哪里/如何进行。
以下是我怀疑它来自pointfree的原因(输出来自GHCI,:pl别名为pointfree):
λ: :pl coordinates s = (x s, y s)
coordinates = liftM2 (,) x y发布于 2014-11-19 23:42:54
这利用了(->) r的(->) r实例,也称为"reader“。这是从特定类型到a的单一函数。(看一看here,了解它存在的原因。)
要了解它如何用于各种函数,请将m替换为m a中的(r ->。例如,如果我们只做liftM,就会得到:
liftM :: (a -> b) -> (m a -> m b)
liftM :: (a -> b) -> ((r -> a) -> (r -> b))
:: (a -> b) -> (r -> a) -> (r -> b) -- simplify parentheses...which只是函数组合。干净利落。
我们可以为liftM2做同样的事情
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)一旦您内化了像这样的多功能组合的想法,像这样的无点代码就变得更加可读性了--不需要使用无点工具!在这种情况下,我认为无点版本仍然更好,但无点版本本身并不可怕。
发布于 2014-11-19 23:36:21
monad liftM2在这里工作,这是函数monad (->) a。正如您之前可能看到的,这相当于Reader 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所以现在如果我们用(,)代替f,用x代替ma,用y代替mb,我们就可以得到
liftM2 (,) x y = do
a <- x
b <- y
return $ (,) a b因为x, y :: Battleship -> Int相当于((->) Battleship) Int,那么m ~ (->) Battleship。函数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")发布于 2014-11-20 08:48:54
你可以很容易地重写
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)这不是毫无意义的风格,但很简单。
https://stackoverflow.com/questions/27028986
复制相似问题