monad如何让我的工作更轻松?给我看一些很酷的代码

时间:2010-10-06 20:03:43

标签: haskell monads

我喜欢阅读有关我不理解的概念的代码片段。是否有任何片段在他们的荣耀中炫耀monad?更重要的是,我如何应用monads使我的工作更轻松。

我大量使用jQuery。这是我所知道的monad的一个很酷的应用。

5 个答案:

答案 0 :(得分:3)

和其他人一样,我认为问题太笼统了。我认为大多数答案(比如我的)会给出一些利用一个特定monad的巧妙的例子。 monad的真正力量在于,一旦你将它们理解为抽象,你就可以将这些知识应用到你遇到的任何新monad中(并且在Haskell中有很多)。这反过来意味着您可以轻松地找出新代码的作用以及如何使用它,因为您已经知道了界面和一些管理其行为的规则。

无论如何,这是一个使用我编写的测试运行脚本中的List monad的示例:

runAll :: IO ()
runAll = do
  curdir <- getCurrentDirectory
  sequence $ runTest <$> srcSets <*> optExeFlags <*> optLibFlags
  setCurrentDirectory curdir

从技术上讲,我正在使用Applicative界面,但如果困扰你,你可以从Control.Monad将<*>更改为ap

关于这一点很酷的是它为列表“srcSets”,“optExeFlags”和“optLibFlags”的每个参数组合调用runTest,以便为每个集合生成分析数据。我认为这比我在C中做的要好得多(3个嵌套循环)。

答案 1 :(得分:2)

你的问题真的很模糊 - 就像问,“展示一个使用变量的代码示例”。它是编程所固有的,任何代码都将成为一个例子。所以,我只是给你一个最近访问过的Haskell函数,它仍然在我的编辑器中打开,并解释了为什么我使用了monadic控制流。

这是我的xmonad配置文件中的代码段。当有一个窗口需要管理时,它是以某种方式运行的布局的实现的一部分,而对于多个窗口则是另一种方式。此函数接收消息并生成新布局。但是,如果我们决定不做任何更改,我们将返回Nothing:

handleMessage' :: AlmostFull a -> SomeMessage -> Int -> Maybe (AlmostFull a)
handleMessage' l@(AlmostFull ratio delta t) m winCount =
  case winCount of
    -- keep existing Tall layout, maybe update ratio
    0 -> finalize (maybeUpdateRatio $ fromMessage m) (Just t)
    1 -> finalize (maybeUpdateRatio $ fromMessage m) (Just t)

    -- keep existing ratio, maybe update Tall layout
    _ -> finalize (Just ratio) (pureMessage t m)
  where
    finalize :: Maybe Rational -> Maybe (Tall a) -> Maybe (AlmostFull a)
    finalize ratio t = ratio >>= \ratio -> t >>= \t ->
      return $ AlmostFull ratio delta t

    maybeUpdateRatio :: Message -> Maybe Rational
    maybeUpdateRatio (Just Shrink) = Just (max 0 $ ratio-delta)
    maybeUpdateRatio (Just Expand) = Just (min 1 $ ratio+delta)
    maybeUpdateRatio _             = Nothing

我们根据当前窗口管理器状态决定返回什么(由X monad中的计算确定,我们将其结果传递给此函数以保持实际逻辑纯净) - 如果有0或1个窗口,我们将消息传递给AlmostFull布局,让它决定做什么。这是f函数。如果消息更改了比率,则返回Just新比率,否则返回Nothing。另一半是相似的;如果有2个或更多窗口,它会将消息传递到Tall的处理程序。如果这是用户要求的布局,则会返回Just个新Tall布局,否则会返回Nothing

finalize函数是有趣的部分;它从ratio包装器中提取t(所需的新比率)和Tall(所需的新Maybe布局)。这意味着两者都必须不是Nothing,否则我们会自动从函数返回Nothing

我们在这里使用Maybe monad的原因是我们可以根据可用的所有结果编写一个函数,而不必编写任何代码来处理出现Nothing的情况。 / p>

答案 2 :(得分:2)

基本上,monad是“势在必行的小语言”。因此,它们使您能够使用任何命令式构造,例如异常(Maybe),记录(Writer),输入/输出(IO),状态(State),非-determinism(列出[a]),解析器(Parsec,ReadP)或其组合。

有关更高级的示例,请查看我的operational package的示例代码。特别是,

  • WebSessionState.lhs实现了Web会话,这些会话被编程为服务器是一个持久进程,而实际上它们是异步传递的。
  • TicTacToe.hs显示了一个游戏引擎,其中玩家和AI被编写为好像他们在并发进程中运行。

答案 3 :(得分:1)

我一直在研究Haskell和信息流安全性。本文非常有趣,它使用Monads在Haskell程序中强制保密。

http://www.cse.chalmers.se/~russo/seclib.htm

答案 4 :(得分:1)

这是我最近做的事情,可能会展示monad的一些力量。这里没有显示实际代码来保护无辜,这只是一个草图。

假设您要搜索某些字典,并根据您发现的内容进行其他搜索。搜索可能会返回Nothing(您要查找的元素不存在),在这种情况下您可能会尝试不同的搜索,如果所有搜索都失败,则返回Nothing。

我们的想法是通过组合monad变换器来制作我们自己的monad,然后我们可以轻松地为搜索创建一些组合器。我们的monad将是ReaderT Dictionary Maybe。我们定义了查找给定键find的函数both,它将返回它在两个搜索中找到的元素列表和oneOf,它会进行两次搜索并尝试首先,如果它没有成功,它会尝试第二个。以下是此类搜索的示例:

import Control.Monad
import Control.Monad.Reader

find a = ReaderT (lookup a)
both a b = liftM2 (++) a b
oneOf = mplus

search = both (find 1) ((find 2) `oneOf` (find 3)) 
         `oneOf` both (find 4) (find 5)

跑步:

(runReaderT search) [(1,"a"),(3,"c"),(4,"d"),(5,"g")] --> Just "ac"

(runReaderT search) [(6,"a")] --> Nothing

我们从monad中获得的巨大优势是我们可以将搜索绑定在一起并将其他函数提升到这个抽象中。比方说,我有两个搜索search_a和search_b,我想做它们然后返回它们合并:

 do a <- search_a
    b <- search_b
    return (merge a b)

liftM2 merge search_a search_b