haskell - 如何在 Haskell 中枚举递归数据类型?

标签 haskell functional-programming grammar monads

This blog post对于如何使用 Omega monad 对角枚举任意语法有一个有趣的解释。他提供了一个示例,说明如何执行此操作,从而产生无限的字符串序列。我想做同样的事情,只不过它不是生成字符串列表,而是生成实际数据类型的列表。例如,

 data T = A | B T | C T T

会生成

A, B A, C A A, C (B A) A... 

或者类似的东西。不幸的是,我的 Haskell 技能仍在成熟,玩了几个小时后我无法做到我想做的事。怎么才能做到这一点?

根据要求,我的尝试之一(我尝试了太多的事情......):

import Control.Monad.Omega

data T = A | B T | C T T deriving (Show)

a = [A] 
        ++ (do { x <- each a; return (B x) })
        ++ (do { x <- each a; y <- each a; return (C x y) })

main = print $ take 10 $ a

最佳答案

我的第一个丑陋方法是:

allTerms :: Omega T
allTerms = do
  which <- each [ 1,2,3 ]
  if which == 1 then
    return A
  else if which == 2 then do
    x <- allTerms
    return $ B x
  else do
    x <- allTerms
    y <- allTerms
    return $ C x y

但是,经过一些清理之后,我到达了这个衬垫

import Control.Applicative
import Control.Monad.Omega
import Control.Monad

allTerms :: Omega T
allTerms = join $ each [return A, B <$> allTerms, C <$> allTerms <*> allTerms]

请注意,顺序很重要:return A 必须是上面列表中的第一个选择,否则 allTerms 将不会终止。基本上,Omega monad 确保选择之间的“公平调度”,使您免于诸如infiniteList++ some,但不阻止无限递归。

<小时/>

Crazy FIZRUK 提出了一个更优雅的解决方案。 ,利用 Omega替代实例。

import Control.Applicative
import Data.Foldable (asum)
import Control.Monad.Omega

allTerms :: Omega T
allTerms = asum [ pure A
                , B <$> allTerms
                , C <$> allTerms <*> allTerms
                ]

关于haskell - 如何在 Haskell 中枚举递归数据类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23515191/

相关文章:

functional-programming - 如果没有可变状态,你怎么能做任何有用的事情?

language-agnostic - 闭包和传统类有什么区别?

python - 从分析树中提取 Chomsky-normal-form 文法

javascript - 如何在 PEG 语法中描述函数参数

Haskell Aeson 与 Sum 类型

function - 这个函数或模式有名字吗?

haskell - 运行 Literate Haskell 代码时没有 (GHC.Base.Alternative Parser) 错误实例

c++ - 模板化类型函数中的模板参数

qml - QML 语法是 LALR(1) 吗?

parsing - Haskell 中 Data.ByteString.Lazy.Char8 的解析器?