希望获得所有方程组合 例如,或(和(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]
答案 0 :(得分:2)
您的第一个代码有几个问题 - 主要是缺少部分(comp
),并且您将树复杂化(在我看来)。
例如,Null
部分似乎很奇怪,您也没有真正包含操作(Or
,And
)。
但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)]
应该很容易以任何你喜欢的形式映射
顺便提一下,有一种明显的方法可以使这些树在连接器(And
,Or
)上通用:
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)
另一个答案是非常深入的。我还想给你的代码编译和运行所需的最小编辑,这样你就可以继续自己探索了。只需要三件事:
getAllTrees
上的类型签名 - 它返回[Tree a]
,而不是Tree a
。Show
个实例。您只需在声明末尾添加deriving Show
,GHC就会为您编写合适的实例。comb
(此处不在范围内)。只需删除提及它的行即可。