如何运行这个树的所有组合

时间:2015-06-05 02:04:07

标签: haskell

希望获得所有方程组合 例如,或(和(A,B),C),或(A,和(B,C))......等

然后我发现一个树的例子似乎接近这个想法,但它有编译错误

main.hs:78:23:
    Couldn't match type `[]' with `Tree'
    Expected type: Tree ([a], [a])
      Actual type: [([a], [a])]
    In the return type of a call of `splits'
    In a stmt of a 'do' block: (left, x : right) <- splits xs
    In the expression:
      do { (left, x : right) <- splits xs;
           Node <$> getAllTrees left <*> pure x <*> getAllTrees right }

main.hs:85:17:
    Couldn't match expected type `[a0]' with actual type `Tree Integer'
    In the return type of a call of `getAllTrees'
    In the second argument of `($)', namely `getAllTrees [1 .. 12]'
    In a stmt of a 'do' block: mapM_ print $ getAllTrees [1 .. 12]

代码:

module Main where
import Data.Foldable (toList)
import Data.List
import Data.Maybe
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Sequence (Seq)
import qualified Data.Sequence as Seq
import Data.Set (Set)
import qualified Data.Set as Set
import Control.Applicative

data Tree x
 = Null
 | Leaf x
 | Node (Tree x) x (Tree x)

splits xs = zip (inits xs) (tails xs)

getAllTrees :: [a] -> Tree a
getAllTrees [] = return Null
getAllTrees [x] = return $ Leaf x
getAllTrees xs = do
 (left, x : right) <- splits xs
 Node <$> getAllTrees left <*> pure x <*> getAllTrees right

main :: IO()
main = do 
  mapM_ print $ splits [1..12]
  mapM_ print comb
  mapM_ print $ getAllTrees [1..12]

2 个答案:

答案 0 :(得分:2)

您的第一个代码有几个问题 - 主要是缺少部分(comp),并且您将树复杂化(在我看来)。 例如,Null部分似乎很奇怪,您也没有真正包含操作(OrAnd)。

splits的想法很有希望!

我允许自己改变你的设计,但这个想法仍然存在。

首先,我将那些And/Or - 树的表示更改为:

data Operation
  = And
  | Or
    deriving Show

data Tree x
 = Leaf x
 | Node (Tree x) Operation (Tree x)
   deriving Show

正如你所看到的那样,它是一个直接的重写 - 只包括操作而不是元素。

我没有在getAllTrees更改你的第一个模式匹配:

getAllTrees :: [a] -> [Tree a]
getAllTrees [] = []
getAllTrees [x] = return $ Leaf x

空列表只返回空列表,单个元素列表将产生Leaf

接下来我们必须决定如何处理split中的那些空白部分(如([],everything)) - 因为它不会真正产生一个有效的树(让我们进入麻烦) - 但是当你开始使用 list-monad 并且有guard可用时,我们可以使用它:

getAllTrees xs = do
  (left, right) <- splits xs
  guard $ not (null left) && not (null right)

而不是使用Applicatives-syntax我发现更容易继续使用monads do样式并递归地从getAllTrees(以及[And,Or]中的运算符)中提取树:

leftT <- getAllTrees left
rightT <- getAllTrees right
op <- [And, Or]

让我们只返回组装的`Node'值:

return $ Node leftT op rightT

为什么guard

问题出现在(fullList, [])

形式的分割中

如果您查看代码,您会看到您将以递归方式反复调用getAllTrees完整列表。

所以,如果警卫不存在,你将获得前几个答案,直到你得到(fullList, [])分裂,然后输出停止并进入无限循环。

你可能想知道为什么你没有看到更多 - 毕竟递归的getAllTrees应该重新你已经看过的那些,这是真的 - 但是rightT <- getAllTrees right不会产生任何结果在right == []这里。

当然,

guard $ not (null right)

就足够了,因为如果左边是空的那么没什么大不了的(因为下一行将通过从空列表中拉出来处理它) - 但我喜欢这里的对称性。

完整来源

import Data.List (inits, tails)
import Control.Monad (guard)

data Operation
  = And
  | Or
    deriving Show

data Tree x
 = Leaf x
 | Node (Tree x) Operation (Tree x)
   deriving Show

splits :: [a] -> [([a], [a])]
splits xs = zip (inits xs) (tails xs)

getAllTrees :: [a] -> [Tree a]
getAllTrees [] = []
getAllTrees [x] = return $ Leaf x
getAllTrees xs = do
  (left, right) <- splits xs
  guard $ not (null left) && not (null right)
  leftT <- getAllTrees left
  rightT <- getAllTrees right
  op <- [And, Or]
  return $ Node leftT op rightT

例如

这将返回例如:

λ> getAllTrees [1..3]
[Node (Leaf 1) And (Node (Leaf 2) And (Leaf 3))
,Node (Leaf 1) Or (Node (Leaf 2) And (Leaf 3))
,Node (Leaf 1) And (Node (Leaf 2) Or (Leaf 3))
,Node (Leaf 1) Or (Node (Leaf 2) Or (Leaf 3))
,Node (Node (Leaf 1) And (Leaf 2)) And (Leaf 3)
,Node (Node (Leaf 1) And (Leaf 2)) Or (Leaf 3)
,Node (Node (Leaf 1) Or (Leaf 2)) And (Leaf 3)
,Node (Node (Leaf 1) Or (Leaf 2)) Or (Leaf 3)]

应该很容易以任何你喜欢的形式映射

明显的概括

顺便提一下,有一种明显的方法可以使这些树在连接器AndOr)上通用:

data Tree x y
 = Leaf x
 | Node (Tree x y) y (Tree x y)
   deriving Show

splits :: [a] -> [([a], [a])]
splits xs = zip (inits xs) (tails xs)

getAllTrees :: [b] -> [a] -> [Tree a b]
getAllTrees _ [] = []
getAllTrees _ [x] = return $ Leaf x
getAllTrees ys xs = do
  (left, right) <- splits xs
  guard $ not (null right)
  leftT <- getAllTrees ys left
  rightT <- getAllTrees ys right
  y <- ys
  return $ Node leftT y rightT

然后你必须致电:

getAllTrees [And,Or] [1..3]

答案 1 :(得分:2)

另一个答案是非常深入的。我还想给你的代码编译和运行所需的最小编辑,这样你就可以继续自己探索了。只需要三件事:

  1. 修复getAllTrees上的类型签名 - 它返回[Tree a],而不是Tree a
  2. 为树提供Show个实例。您只需在声明末尾添加deriving Show,GHC就会为您编写合适的实例。
  3. 决定如何处理comb(此处不在范围内)。只需删除提及它的行即可。