1

私はHaskellを初めて使用し、プログラムがリストの最後に到達したときにプログラムが爆発するのを止める方法を見つけようとしています.

例として、XY軸に関する文字のリストのリストをミラーリングする関数があります。

なしでこれをどのように書き直すことができtakeますか?

mirrorXY' :: [[a]] -> [[a]]
mirrorXY' m = (map head m) : mirrorXY' (map tail m)
mirrorXY m = take (length $ m!!0) $ mirrorXY' m

PS を見つけたばかりですがtranspose、まだ回答が欲しいです。

4

2 に答える 2

4

まず、 直接再帰の代わりにmirrorXY'高階関数mapを使用して記述できます。iterate

mirr m = map (map head) . iterate (map tail) $ m

...そして、あなたが発見したように、これは空のリストにヒットすると爆発します:

*Main> map (map head) . iterate (map tail) $ [[1..4],[2..5],[3..6]]
[[1,2,3],[2,3,4],[3,4,5],[4,5,6],[*** Exception: Prelude.head: empty list

最初の部分なしで試してみましょう:

*Main> iterate (map tail) $ [[1..4],[2..5],[3..6]]
[[[1,2,3,4],[2,3,4,5],[3,4,5,6]],[[2,3,4],[3,4,5],[4,5,6]],[[3,4],[4,5],[5,6]],[
[4],[5],[6]],[[],[],[]],[*** Exception: Prelude.tail: empty list
*Main>

[]したがって、修正は簡単です。入力リストでを押すのをやめるだけです。

*Main> takeWhile (not.null.head) . iterate (map tail) $ [[1..4],[2..5],[3..6]]
[[[1,2,3,4],[2,3,4,5],[3,4,5,6]],[[2,3,4],[3,4,5],[4,5,6]],[[3,4],[4,5],[5,6]],[
[4],[5],[6]]]

したがって、関数は

mirr xs = map (map head) . takeWhile (not.null.head) . iterate (map tail) $ xs

これは、すべてのサブリストが同じ長さ (または少なくとも最初のリストが最も短い) であることを前提としていますが、これは のテストを微調整することで簡単に修正できますtakeWhile

mirr xs = map (map head) . takeWhile (all (not.null)) . iterate (map tail) $ xs
于 2012-07-06T12:30:15.033 に答える
2

空のリストを処理する必要があります。

mirrorXY [] = []
mirrorXY ([]:_) = []
mirrorXY m = (map head m) : mirrorXY (map tail m)

これは、リストの長さが均一であることを前提としています。

より堅牢に、次のようなもの

safeHead [] = Nothing
safeHead (a:_) = Just a

mirrorXY [] = []
mirrorXY m = case mapM safeHead m of
               Nothing -> []
               Just a -> a : mirrorXY (map tail m)

短すぎる最初のリストで停止します。これはs モナドインスタンスを使用して、回線Maybeを介して短絡を行うことに注意してください。mapM safeHead m


を使用して、最後のバージョンをよりコンパクトに書くことさえできますmaybe:

mirrorXY [] = []
mirrorXY m = maybe [] (: mirrorXY (map tail m)) $ mapM safeHead m

しかし、これは必ずしも明確ではありません。

于 2012-07-06T12:31:15.060 に答える