在应用函数monad之前对输入执行转换

lhc*_*tti 2 monads lambda haskell

我知道我可以使用函数monad来实现类似下面的构造(我在多个调用中重用参数而不显式引用它):

compute_v0 :: String -> String
compute_v0 = do 
    x <- length -- (using the argument implicitly here)
    top <- head -- (and here)
    return (replicate x top)
Run Code Online (Sandbox Code Playgroud)

上述函数的结果是: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)
Run Code Online (Sandbox Code Playgroud)

现在的结果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
Run Code Online (Sandbox Code Playgroud)

但是我仍然需要包含一个lambda,使用很多let绑定并显式引用lambda参数.是否有更好的方法来实现这样的结构?

Dav*_*vid 5

由于所有Monad实例都有Functor实例和函数实例Functorhas fmap = (.),您可以拥有

compute :: String -> String 
compute = flip fmap (++ "abcd") $ do
    x   <- length
    top <- head
    return $ replicate x top
Run Code Online (Sandbox Code Playgroud)

一些包(比如microlenslens)定义(<&>) = flip fmap,允许你写

compute :: String -> String 
compute = (++ "abcd") <&> do
    x   <- length
    top <- head
    return $ replicate x top
Run Code Online (Sandbox Code Playgroud)

还有一个Category实例(->),它给了我们(>>>) = flip (.).这可能会在视觉上更加清晰:

compute :: String -> String 
compute = (++ "abcd") >>> do
    x   <- length
    top <- head
    return $ replicate x top
Run Code Online (Sandbox Code Playgroud)