在应用函数 monad 之前对输入执行转换
Executing a transformation to the input before applying the function monad
我知道我可以使用函数 monad 来实现如下所示的构造(我在多个调用中重用该参数而没有显式引用它):
compute_v0 :: String -> String
compute_v0 = do
x <- length -- (using the argument implicitly here)
top <- head -- (and here)
return (replicate x top)
上述函数的结果:compute "1234"
将是 "1111"
我的问题是:在执行 do 块之前如何对 'hidden' 参数应用转换(假设我想将 "abcd" 附加到列表)。
我的第一个解决方案:
compute_v1 :: String -> String
compute_v1 = compute_v1' . (++ "abcd")
compute_v1' ::String -> String
compute_v1' = do
x <- length
top <- head
return (replicate x top)
compute "1234"
的结果现在为 "11111111"
。这实际上完成了工作,但我宁愿尝试将其全部定义在一个简洁的代码块中。
我最接近实际包含转换同时仍然保持代码 (v0) 样式的是这个:
compute_v2 :: String -> String
compute_v2 = (++ "abcd") >>= \r -> do
let x = length r
let top = head r
return $ replicate x top
但我仍然必须包含一个 lambda,使用大量 let 绑定并显式引用 lambda 参数。有没有更好的方法来实现这样的构造?
因为所有 Monad
个实例也有 Functor
个实例并且 Functor
的函数实例有 fmap = (.)
,你可以有
compute :: String -> String
compute = flip fmap (++ "abcd") $ do
x <- length
top <- head
return $ replicate x top
一些包(如 microlens
和 lens
)定义 (<&>) = flip fmap
,允许您编写
compute :: String -> String
compute = (++ "abcd") <&> do
x <- length
top <- head
return $ replicate x top
(->)
还有一个 Category
实例,它给我们 (>>>) = flip (.)
。从视觉上看,这可能会更清楚一些:
compute :: String -> String
compute = (++ "abcd") >>> do
x <- length
top <- head
return $ replicate x top
你可以这样做:
compute_v2 :: String -> String
compute_v2 = do
x <- length
top <- head
return $ replicate x top
<$> (++ "abcd")
AFAIK,有问题的 monad 称为 Reader monad,它也是一个 Functor
.
*Q46393211> compute_v2 "1234"
"11111111"
*Q46393211> compute_v2 "71"
"777777"
MonadReader
class为此有方法local
,(->) r
是一个实例,所以
import Control.Monad.Reader (local)
compute_v3 ::String -> String
compute_v3 = local (++ "abcd") $ do
x <- length
top <- head
return (replicate x top)
应该可以(目前无法测试)。
我知道我可以使用函数 monad 来实现如下所示的构造(我在多个调用中重用该参数而没有显式引用它):
compute_v0 :: String -> String
compute_v0 = do
x <- length -- (using the argument implicitly here)
top <- head -- (and here)
return (replicate x top)
上述函数的结果:compute "1234"
将是 "1111"
我的问题是:在执行 do 块之前如何对 'hidden' 参数应用转换(假设我想将 "abcd" 附加到列表)。
我的第一个解决方案:
compute_v1 :: String -> String
compute_v1 = compute_v1' . (++ "abcd")
compute_v1' ::String -> String
compute_v1' = do
x <- length
top <- head
return (replicate x top)
compute "1234"
的结果现在为 "11111111"
。这实际上完成了工作,但我宁愿尝试将其全部定义在一个简洁的代码块中。
我最接近实际包含转换同时仍然保持代码 (v0) 样式的是这个:
compute_v2 :: String -> String
compute_v2 = (++ "abcd") >>= \r -> do
let x = length r
let top = head r
return $ replicate x top
但我仍然必须包含一个 lambda,使用大量 let 绑定并显式引用 lambda 参数。有没有更好的方法来实现这样的构造?
因为所有 Monad
个实例也有 Functor
个实例并且 Functor
的函数实例有 fmap = (.)
,你可以有
compute :: String -> String
compute = flip fmap (++ "abcd") $ do
x <- length
top <- head
return $ replicate x top
一些包(如 microlens
和 lens
)定义 (<&>) = flip fmap
,允许您编写
compute :: String -> String
compute = (++ "abcd") <&> do
x <- length
top <- head
return $ replicate x top
(->)
还有一个 Category
实例,它给我们 (>>>) = flip (.)
。从视觉上看,这可能会更清楚一些:
compute :: String -> String
compute = (++ "abcd") >>> do
x <- length
top <- head
return $ replicate x top
你可以这样做:
compute_v2 :: String -> String
compute_v2 = do
x <- length
top <- head
return $ replicate x top
<$> (++ "abcd")
AFAIK,有问题的 monad 称为 Reader monad,它也是一个 Functor
.
*Q46393211> compute_v2 "1234"
"11111111"
*Q46393211> compute_v2 "71"
"777777"
MonadReader
class为此有方法local
,(->) r
是一个实例,所以
import Control.Monad.Reader (local)
compute_v3 ::String -> String
compute_v3 = local (++ "abcd") $ do
x <- length
top <- head
return (replicate x top)
应该可以(目前无法测试)。