ice*_*man 6 haskell pointfree lifting
我正在审查一些代码,并遇到了以下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
Run Code Online (Sandbox Code Playgroud)
有人会善意地解释简化所需的步骤:
(i)coordinates b = (x b, y b)
到:
(ii)coordinates = liftM2 (,) x y
?
特别是,我对使用有点困惑,liftM2
因为我甚至不知道monad潜伏在后台.
我知道(i)也可以表示为:coordinates s = (,) (x s) (y s)
但我不知道在哪里/如何继续.
PS以下是我怀疑它来自pointfree
(输出来自GHCI
和:pl
别名pointfree
)的原因:
?: :pl coordinates s = (x s, y s)
coordinates = liftM2 (,) x y
Run Code Online (Sandbox Code Playgroud)
这利用了Monad
实例(->) r
,也称为"读者monad".这是从特定类型到函数的monad a
.(看看这里为什么它存在于第一位的动机.)
要了解它如何适用于各种功能,请m
使用(r ->
in 替换m a
.例如,如果我们这样做liftM
,我们得到:
liftM :: (a -> b) -> (m a -> m b)
liftM :: (a -> b) -> ((r -> a) -> (r -> b))
:: (a -> b) -> (r -> a) -> (r -> b) -- simplify parentheses
Run Code Online (Sandbox Code Playgroud)
......这只是功能构成.整齐.
我们可以做同样的事情liftM2
:
liftM2 :: (a -> b -> c) -> m a -> m b -> m c
liftM2 :: (a -> b -> c) -> (r -> a) -> (r -> b) -> (r -> c)
Run Code Online (Sandbox Code Playgroud)
所以我们看到的是用两个参数函数组合两个单参数函数的方法.这是将正常函数组合推广到多个参数的一种方法.我们的想法是创建一个函数,r
通过传递两个单参数函数来获取单个函数,将两个参数传递给双参数函数.所以如果我们有f :: (r -> a)
,g :: (r -> b)
并且h :: (a -> b -> c)
我们生产:
\ r -> h (f r) (h r)
Run Code Online (Sandbox Code Playgroud)
现在,这如何适用于您的代码?(,)
是两个参数的功能,x
以及y
是类型的一个参数的功能Battleship -> Int
(因为这是场存取的工作方式).考虑到这一点:
liftM2 (,) x y = \ r -> (,) (x r) (y r)
= \ r -> (x r, y r)
Run Code Online (Sandbox Code Playgroud)
一旦你内化了像这样的多功能组合的想法,像这样的无点代码变得更加可读 - 不需要使用pointfree工具!在这种情况下,我认为非无版本的版本仍然更好,但是无点版本本身并不可怕.
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
Run Code Online (Sandbox Code Playgroud)
所以现在,如果我们替换(,)
为for f
,x
for ma
和y
for mb
,我们得到
liftM2 (,) x y = do
a <- x
b <- y
return $ (,) a b
Run Code Online (Sandbox Code Playgroud)
由于x, y :: Battleship -> Int
这相当于((->) Battleship) Int
,然后m ~ (->) Battleship
.函数monad定义为
instance Monad ((->) a) where
return x = const x
m >>= f = \a -> f (m a) a
Run Code Online (Sandbox Code Playgroud)
本质上monad所做的功能是允许你从几个函数中提取输出,只要它们都具有相同的输入.一个更清晰的例子可能是这样的
test = do
a <- (^2)
b <- (^3)
c <- (^4)
d <- show
return (a, b, c, d)
> test 2
(4, 8, 16, "2")
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
234 次 |
最近记录: |