应用功能单子

问题描述:

我知道我可以使用函数单子来实现类似下面的一个结构(在这里我重复使用多次调用的参数不明确引用它)之前执行转换到输入:应用功能单子

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"

我的问题是:我将如何执行做块之前应用转换到“隐藏”的说法(想象一下,我想追加“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 

但我还是必须包括一个拉姆达,使用了大量的let绑定的并明确引用lambda参数。有更好的方法来实现这样的结构吗?

+0

'compute_v1 = liftA2重复长度头。 (++“abcd”)' – 4castle

+0

'compute_v1 =(复制长度头)。 (++“abcd”)' – Redu

由于所有Monad情况下,也有Functor实例和Functor功能实例有fmap = (.),你可以有

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

有些软件包(如microlenslens)定义(<&>) = flip fmap,让你写

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

(->)也有一个Category实例,其中giv es我们(>>>) = flip (.)。这可能会稍微更清晰,视觉:

compute :: String -> String 
compute = (++ "abcd") >>> do 
    x <- length 
    top <- head 
    return $ replicate x top 
+0

我伪装成'(。)'时不会使用'fmap'。我会使用'flip(。)(++“abcd”)'或'(。(++“abcd”))''。(嗯,说实话,我绝对不会写这个monadic风格,但OP似乎想要试验这个) – chi

+0

@chi这是一个很好的观点,但我想突出思考过程有点让我想起它(这是因为我们正在使用它的monadic属性,请尝试查看'Functor'实例的功能)。 –

+0

我明白了。是的,我同意这个过程。 – chi

你可以做这样的事情:

compute_v2 :: String -> String 
compute_v2 = do 
    x <- length 
    top <- head 
    return $ replicate x top 
    <$> (++ "abcd") 

据我所知,有问题的单子被称为读者单子,并且它也是一个Functor

*Q46393211> compute_v2 "1234" 
"11111111" 
*Q46393211> compute_v2 "71" 
"777777" 
+1

@chi GHCi中加载的模块中的代码没有解析错误。我还没有尝试'真正'编译它... –

+0

我喜欢这些“简单”的Haskell问题和答案,他们总是让我的脑袋迅速旋转。我目前对此有所了解:''是'fmap'的中缀运算符(查找[here](https://stackoverflow.com/questions/37286376/what-does-mean-in-haskell))。左边的任何东西都是一个函数'a-> b',右边是'f a'。所以这是一个函数?对于'do'块本身,这是'List' monad,因为字符串是字符列表? –

+0

@StefanHanke不,它一直是函数monad(和函数函子)。 “(++“abcd”)'。如果我有这样的事情,我会亲自把这些包裹放在明确的位置。 –

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) 

应该工作(不能在此刻测试)。