2016-03-18 16 views
0

私はhaskellでツリーの子を逆転しようとしています。私は、これは100%に動作するかどうかさえわからないハスケル:ツリーの子を再帰的に逆にするには

rev :: Tree v e -> Tree v e 
rev (Node v []) = Node v [] 
rev (Node v xs) = 
    let xs' = (rev'(snd (unzip xs))) 
    in Node v (zip (fst (unzip xs)) (map rev xs')) 


rev' :: [Tree v e] -> [Tree v e] 
rev' [] = [] 
rev' (x:xs) = (rev' xs) ++ [x] 

:私はこの2つの機能でそれを行う現時点で

data Tree v e = Node v [(e,Tree v e)] 

:ツリーは次のようになります。 1つの関数で再帰的に行う方法はありますか?自分の道が非効率的だと感じる。

revRec :: Tree v e -> Tree v e 
revRec (Node v [])  = Node v [] 
revRec (Node v (x:xs)) = Node v (revRec xs ++ [x]) 

Obviosuly私はxsリスト以来xsrevRecを呼び出すことはできません:私はこのようになります関数を記述しようとしていました。私はちょうど私がそれが難しくないshoudn'tのように感じるにもかかわらず私はちょうどこの問題のまわりで私の頭を包むことができない。

+1

、あなたも '回転を必要としない(ノードV [])= .. 'の場合、一般的なリストの場合は空のリストの場合もカバーします。第2に、 'unzip'を使うことは完全に合理的なようです - ' fst'と 'snd'(' unzip'への複数の呼び出し)の使用はおそらくなくすべきです。たとえば、プリミティブな再帰で書くことができます。 $ foldr(\(e、t)(as、bs) - >(e:as、bs。(rev)) 'rev(Node a ts)=ノードa $ uncurry(\ xy-> zip x t :)))([]、id)ts'である。しかし、私はこれが 'unzip/reverse'バージョンよりも効率的であることを本当に疑っています(それは確かに醜いです)。 – user2407038

答えて

2

ゼロスは、コードをクリーンアップします。あなたはそれらの多くの括弧を必要とせず、重複計算を避けるべきです。 fstsndは同じものを2回使用していますか? Meh。活用のパターンマッチング:

rev :: Tree v e -> Tree v e 
rev (Node v xs) 
    = let (es, cs) = unzip xs 
     xs' = rev' cs 
    in Node v $ zip es (map rev xs') 

rev' :: [Tree v e] -> [Tree v e] 
rev' [] = [] 
rev' (x:xs) = rev' xs ++ [x] 

rev'がすべてで、木々のリストに固有のものではないことをまずノート!ただreverse機能の非効率的な実装です。これはどのリストでも機能します。

第2のでは、このアンジッピング/ジップは少しぎこちない。これは実際にあなたが望むふるまいであると確信していますか?現在、子供のリストを逆転させているだけですが、の要素の順番は同じです。そうでない場合は、あなたがより良い1つの逆と一つのマップでそれをすべて行うだろう:

rev :: Tree v e -> Tree v e 
rev (Node v xs) = Node v . reverse $ map (\(e,c) -> (e, rev c)) xs 

または、でもよりよい、まず

import Control.Arrow 

rev (Node v xs) = Node v . reverse $ map (second rev) xs 
+1

効率のよい点:良い理由(本当に私が約束します)では、「逆」はリスト融合に関与しません。したがって、 '逆。マップfは、理想的には、「mapReverse」(明白な意味で構成した名前)のアプリケーションに手作業で融合する必要があります。 – dfeuer

+0

落ち着いた教訓的なポイント:「Arrow」抽象化は、自分のような中級レベルのハスケラーにも威圧しています。したがって、代わりに 'Data.Bifunctor'の' second'を使うことを強くお勧めします。 「Bifunctor」は、初心者に優しい抽象であるIMOです。 – dfeuer

+0

'(、)'にFunctorインスタンスを使うのはどうですか?私が正しく覚えていれば、それは 'second'と同じです。 – epsilonhalbe

関連する問題