【问题标题】:Where can I learn advanced Haskell? [closed]我在哪里可以学习高级 Haskell? [关闭]
【发布时间】:2011-01-08 16:53:20
【问题描述】:

在对one of my answers 的评论中,SO 用户 sdcwc 基本上指出了以下代码:

comb 0 = [[]]

comb n =
    let rest = comb (n-1)
    in  map ('0':) rest
     ++ map ('1':) rest

可以替换为:

comb n = replicateM n "01"

这让我完全惊呆了。

现在我正在寻找教授这些高级概念的教程、书籍或 PDF。我不是在寻找针对初学者的“什么是单子”教程或解释replicateM 类型的在线参考。我想学习如何在单子中思考并有效地使用它们,如果你愿意的话,是单子“模式”。

【问题讨论】:

  • 你可能找不到一本书可以为你做到这一点。这需要时间和思想上的重大转变。只需在 Haskell 中编程。很多。将其用于实际项目。参与社区,打高尔夫球,应用等式推理,玩。
  • 这也不是什么先进的概念,考虑到所有的事情。它只是一个高阶函数和列表单子。 Grok list monad,你可以 grok 这段代码。

标签: haskell design-patterns monads


【解决方案1】:

sequencefilterMliftM2join 之类的函数为例,思考它们如何为每个 monad IO[](->) aWriterState 工作。例如,sequence for IO monad 顺序执行 IO 动作:

 [IO a] -> IO [a]

写下签名并尝试使用它们。有些组合很有趣,有些则不那么有趣。

过滤器示例:

{-# LANGUAGE NoMonomorphismRestriction #-}
import Control.Monad
import Control.Monad.State
import Control.Monad.Reader

a = filterM (\x -> do putStrLn $ "Put " ++ show x ++ "?"
                      fmap (=="Y") getLine)

b = filterM (const [False,True])

c m xs = runState (filterM k xs) 0
              where k x = do a <- get
                             let p = a + x <= m
                             when p $ put (a+x)
                             return p

d = filterM (flip id)

a 使用 IO 过滤列表 - 它向用户询问每个项目。

b 不确定地过滤列表 - 每个项目都不确定地包括和不包括在内。结果,您获得了powerset。 (试试看!)

c 过滤列表,保持状态。在这种情况下,这是一个贪婪的背包 - 你有容量为 m 的背包,并且想要从 xs 插入尽可能多的项目。

d 过滤列表,保持只读状态。这并不有趣。我使用过滤函数作为状态,这给出了flip filter

单个函数filterM 可以完成所有这些事情。

如果您为其他函数编写类似的代码,您将获得足够的直觉来注意到其他地方的单子函数。比如下面的函数如何获取?

dup f x = f x x

那么dup' f x = f x x x呢?

【讨论】:

  • 非常有用的答案,谢谢!海事组织这需要更多的赞成票。你能透露dupdup'的定义吗?
  • @Philip K:Haskell 中的类型总是一个很好的指南。 dup :: (r -&gt; r -&gt; a) -&gt; r -&gt; a。将r -&gt; 缩短为m,这是m (m a) -&gt; m a。因此 dup = join 用于 (-&gt;) r monad,在 Control.Monad.Instances 中可用。 dup' = join . join。一般情况下,join . join :: m (m (m a)) -&gt; m a.
【解决方案2】:

从我的角度来看(这当然不是通用的),我对 list monad 漠不关心 - 在你的例子中,我会(弱)争辩说,由于有很多列表函数,它就像一个巧合一样好该解决方案是一元函数,而不仅仅是列表函数(或通过 Data.Traversable 或 Data.Foldable 对列表函数的概括)。

对于单子模式,我更多地考虑效果而不是特定的组合器 - 状态模型读写状态,阅读器模型只读“状态”,写入器模型只写“状态”,Maybe 模型偏向性(因此它可以在没有错误的情况下建模错误错误消息),Either/Error 使用有形的错误代码或消息对错误建模。当您掌握效果时 - 您很快意识到您需要将它们组合起来,这样 monad 转换器就变得很重要。

除了“编程的乐趣”之外,还没有任何关于高级 Haskell 的书籍——这是一本多作者的书,收集了一些完全不同的作品,所以在决定是否是一本你的书之前,值得先浏览一下。会想要的。 Richard Bird 的新书有许多高级编码的例子,但它使用简单、优雅的代码来做到这一点。这是一本非常好的书,虽然它不是一本关于高级语言功能的书。

在没有书籍的情况下,论文是最好的地方,因为它们比博客更精致。最相关的是 Haskell Symposium(以前称为 Haskell 研讨会),请查看下面的链接以获取列出所发表论文的会议记录,然后搜索您发现有趣的任何内容 - 在大多数情况下,作者会公开发表论文可用。

http://haskell.org/haskell-symposium/

【讨论】:

    【解决方案3】:

    这段代码实际上结合了关于 Haskell 的两个非常隐含的事实:

    • 默认情况下,字符串是字符列表
    • 这些列表是不确定性 monad 的一种实现,它在组合时枚举所有可能的路径。

    以下代码片段是等价的:

    replicateM n "12"
    
    replicateM n ['1', '2']
    
    replicateM n $ do c <- ['1', '2']
                      return c
    

    我认为最后一个版本实际上最清楚地显示了在这种情况下发生的情况:我们可以在“1”和“2”之间进行选择,并且这些选择中的 n 个被链接在一起。一旦你理解了这一点,你对 Haskell 的理解就会达到你需要的水平。其余的只是一个很好的混淆。

    【讨论】:

      【解决方案4】:

      monad 真正狂野/令人敬畏的地方在于,当您超越 state monad 及其子集(编写器和读取器)并开始考虑 Cont 和 List 以及它们在回溯、组合和搜索方面的含义时。稍后我会提供更多参考,但 Oleg 和 Chung-jieh Shan 的 LogicT 论文是一个好的开始:http://okmij.org/ftp/Computation/monads.html

      EZ Yang 在 MR 15 中的三个单子中的冒险:http://themonadreader.files.wordpress.com/2010/01/issue15.pdf

      这个问题的答案可能也很有趣:Creative uses of monads

      【讨论】:

        【解决方案5】:

        查看TMR13 中的 Typeclassopedia。没有人建议过它,它帮助我思考 Haskell 提供的各种类型类。

        注意:它正在更新为second edition,但第一版仍然相关且内容丰富。

        【讨论】:

        【解决方案6】:

        http://learnyouahaskell.com/http://www.realworldhaskell.org/blog/ 是我了解 Haskell 语言的好概念的两个很好的资源,您可以在线免费使用它们。) - 我希望他们可以进一步给您一些不错的步骤。即使他们不教授最先进的概念,他们也可以让您很好地了解那里有什么以及它可能有用的地方。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-03-06
          • 1970-01-01
          • 1970-01-01
          • 2010-10-02
          • 2011-06-22
          • 1970-01-01
          • 2010-09-15
          相关资源
          最近更新 更多