将(可能是一元的)函数递归地应用到自身上

时间:2015-10-15 11:14:15

标签: haskell grammar l-systems

我试图在Haskell https://en.m.wikipedia.org/wiki/L-system中表达一个L系统,特别是Lindenmayer的原始L系统,用于模拟藻类的生长。

  

变量:A B
  常数:无
  公理:A   规则:(A→AB),(B→A)

对我来说,解决这个问题的自然方法是将规则应用于列表中的每个元素,这对我来说意味着我可以使用某种类型的字符串替换来为解决方案建模。

实施例

对于“字符”列表[A,B,A我们应用规则并得到[A→AB,B→A,A→AB] = [A,B,A,A,B](为了让这个模型与Haskell很好地配合,你必须将AB视为一个列表[A,B],我们将与上述规则产生的任何其他结果相结合。)

我已经生成了下面的代码,其中包含数据构造函数,不必处理除A或B之外的其他字符,

data Letter = A | B deriving (Show, Eq)

type Alphabet = [Letter]

algae :: Alphabet -> Alphabet

algae = concat . map (\c -> if
                | c == A -> A:[B]
                | c == B -> [A])

上面的代码是这样的,用它自己作为参数调用它会产生预期的结果,即。该

algae $ algae $algae [A] =  [A, B, A, A, B]

重复的应用程序按预期工作。

我接下来想要完成的是函数递归地应用到自身,但未能表达这一点。我的意思是我希望能够调用该函数,可以是algae [A],也可以是algae(这需要将类型签名更改为algae :: Alphabet),这会产生无限列表通过无限次地将藻类施加到自身上来获得它。

由于我已经承认失败,我已经查看了http://hackage.haskell.org/package/lindenmayer-0.1.0.0/docs/Lindenmayer-D0L.html,但我无法理解代码(还),还发现了其他同样令人困惑的实现。

我已尽力尝试使用foldsfix功能,但未能这样做。我也尝试借用其他递归定义,例如

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

但是这种方法失败,因为zipWith期望二元运算符。 没有monads可以解决这个问题吗?如果是这样,怎么样?

2 个答案:

答案 0 :(得分:5)

您可以使用iterate。我还建议您对algae函数稍作修改以使用模式匹配:

data Letter = A | B deriving (Show, Eq)

type Alphabet = [Letter]

algae :: Alphabet -> Alphabet
algae = concatMap f
  where f A = [A, B]
        f B = [A]

infAlgae :: [Alphabet]
infAlgae = iterate algae [A]

main :: IO ()
main = print $ infAlgae !! 3 

答案 1 :(得分:4)

我认为您可能也对如何有效地生成实际无限列表感兴趣,fibs样式:

import Data.List (stripPrefix)

data Letter = A | B deriving (Show, Eq)

type Alphabet = [Letter]

algae :: Alphabet -> Alphabet
algae = concatMap f
  where f A = [A, B]
        f B = [A]

infFromPrefix :: Eq a => ([a] -> [a]) -> [a] -> [a]
infFromPrefix rule prefix = inf where
    inf = prefix ++ case stripPrefix prefix (rule inf) of
        Just suffix -> suffix
        Nothing     -> error "Substitution does not preserve prefix"

infAlgae :: Alphabet
infAlgae = infFromPrefix algae [A]

main :: IO ()
main = print . take 100 $ infAlgae

在GHCi中:

*Main> :main
[A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A,A,B,A]