のMaybe
定義により、 はツリーの最上位でのみ使用できますTree a
。これは 'pure' の変換のみを回避しEmptyTree
ます。対象の型に同等の値が存在できないため、これは良い音です。次に、私の最初の回答で述べたように、後の発生に対応する唯一の方法EmptyTree
は、リストの線形再帰的な性質を利用して、それらを簡単にスキップできるようにすることです。
最後に、最上位ノードでは、結果をMaybe
型にラップして、pure の変換を回避する必要がありEmptyTree
ます。そうすれば、心配することなくサブフォレストに合理的に取り組むことができます。
これは、従うのが最も簡単なこのバージョンにつながります。
convertGTree :: GeneralTree a -> Maybe (Tree a)
convertGTree EmptyTree = Nothing
convertGTree (GNode a forestGTree) = Just (Node a forest)
where
forest = buildForest forestGTree
buildForest :: [GeneralTree a] -> [Tree a]
buildForest [] = []
buildForest (x:xs) = case x of
GNode n forest -> (Node n (buildForest forest)) : (buildForest xs)
_ -> buildForest xs
イラストテスト、
>>> let testGeneralTree = GNode "0" [GNode "1" [GNode "2" [], EmptyTree], GNode "3" [EmptyTree]]
>>> putStrLn . drawTree . fromJust . convertGTree $ testGeneralTree
0
|
+- 1
| |
| `- 2
|
`- 3
unfoldTree を使用して Tree を返す (おそらく a)
まず、データ コンストラクターに Node を使用しないでください。これは、既に Tree データ型で使用されているためです。そうしないと、名前の競合が発生します。このように再定義することにした理由は、
data GeneralTree a = EmptyTree | GNode a [GeneralTree a]
deriving (Show)
EmptyTree
これは、中間Maybe
型を使用して対処できます。
まず、舞台裏buildSafeTree
で使用する関数を渡します。
ケースを管理し、値に遭遇したときに Nothing を返すヘルパー ヘルプ。
安全なツリーが構築されると、 を使用してそれをきれいにすることができます。トリックは、ステートメントのケースごとに値をスキップすることにあります。unfoldTree
EmptyTree
cleanSafeTree
cleanForest
Nothing
以下のコード、
testGeneralTree = GNode "0" [GNode "1" [GNode "2" [], EmptyTree], GNode "3" [EmptyTree]]
convertTree :: GeneralTree a -> Tree a
convertTree = cleanSafeTree . buildSafeTree
buildSafeTree :: GeneralTree a -> Tree (Maybe a)
buildSafeTree =
unfoldTree helper
where
helper :: GeneralTree a -> (Maybe a, [GeneralTree a])
helper EmptyTree = (Nothing, [])
helper (GNode a trees) = (Just a, trees)
cleanSafeTree :: Tree (Maybe a) -> Tree a
cleanSafeTree tree@(Node (Just root) forest) =
Node root (cleanForest forest)
where
cleanForest :: Forest (Maybe a) -> Forest a
cleanForest [] = []
cleanForest (x:xs) = case x of
Node Nothing _ -> cleanForest xs
Node (Just x) trees -> (Node x (cleanForest trees)) : (cleanForest xs)
いくつかのテスト、
>>> testGeneralTree
GNode "0" [GNode "1" [GNode "2" [],EmptyTree],GNode "3" [EmptyTree]]
>>> putStrLn . drawTree . convertTree $ testGeneralTree
0
|
+- 1
| |
| `- 2
|
`- 3
>>> putStrLn . drawTree . fmap show . buildSafeTree $ testGeneralTree
Just "0"
|
+- Just "1"
| |
| +- Just "2"
| |
| `- Nothing
|
`- Just "3"
|
`- Nothing
使用unfoldForest
は短くなります。
convertTrees :: GeneralTree a -> Tree a
convertTrees (GNode a forest) =
Node a (cleanForest . unfoldForest helper $ forest)
where
-- build a Forest of Tree (Maybe a) from GeneralTree a
toTreeMaybe :: GeneralTree a -> (Maybe a, [GeneralTree a])
toTreeMaybe EmptyTree = (Nothing, [])
toTreeMaybe (GNode a subForest) = (Just a , subForest)
-- Clean the Maybe a, for a Forest of Tree Maybe a
fromMaybe :: Forest (Maybe a) -> Forest a
fromMaybe [] = []
fromMaybe (x:xs) = case x of
Node Nothing _ -> cleanForest xs
Node (Just x) trees -> (Node x (cleanForest trees)) : (cleanForest xs)
UnfoldTreeM を使用して返すモナディック バージョンMaybe (Tree a)
を使用したソリューションunfoldTreeMonadic
convertMonadicTrees :: GeneralTree a -> Maybe (Tree a)
convertMonadicTrees = unfoldTreeM helper where
helper :: GeneralTree a -> Maybe (a, [GeneralTree a])
helper EmptyTree = Nothing
helper (GNode a trees) = Just (a, trees)
主な違いは、GeneralTree に EmptyTree 値が含まれている場合は破棄されるため、何も返さないことです。
>>> testGeneralTree2
GNode 0 [GNode 1 [GNode 2 [],EmptyTree],GNode 3 [EmptyTree]]
>>> convertMonadicTrees testGeneralTree2
Nothing