折りたたみ後の後処理ステップなしでこの単語機能を実装することは可能ですか?


14

印刷物のReal World Haskell、第4章、98ページでは、words折りたたみを使用して実装できるかどうかを尋ねられますが、これも私の質問です。

出来ますか?そうでない場合、なぜですか?もしそうなら、どうですか?

私は次のことを思いつきました、これは各非スペースが出力リストの最後の単語の前に追加されるべきであるという考えに基づいています(これはotherwiseガードで発生します)、そして空白は空の単語の追加をトリガーするべきであるという考えに基づいています出力リストがまだ存在しない場合(これがで取り扱われますif- - )。thenelse

myWords :: String -> [String]
myWords = foldr step [[]]
  where
    step x yss@(y:ys)
      | x == ' ' = if y == "" then yss else "":yss
      | otherwise = (x:y):ys

入力文字列の先頭にスペースがあると、文字列の出力リストに1つの空の文字列が先行するため、このソリューションは間違いです。

上記のリンクで、私は他の読者のために提案された解決策のいくつかを調べました、そしてそれらの多くは私の解決策と同様に動作しますが、それらは一般的に、例えば、tailもしあるならそれを空の先行文字列です。

他のアプローチはタプル(実際にはペアのみ)を使用するため、フォールドはペアを処理し、先頭/末尾のスペースを適切に処理できます。

これらすべてのアプローチfoldr(または別のフォールド、fwiw)は、箱から出して最終的な出力を提供する関数ではありません。なんとかして出力を調整しなければならない何かが常にあります。

したがって、私は最初の質問に戻って、words折りたたみを使用して(末尾/先頭/繰り返しのスペースを正しく処理する方法で)実際に実装できるかどうかを尋ねます。折り目を使用して、私は折りたたみ機能は、最も外側の関数でなければならないことを意味します。

myWords :: String -> [String]
myWords input = foldr step seed input

回答:


13

私が正しく理解していれば、要件には

(1) words "a b c" == words " a b c" == ["a", "b", "c"]
(2) words "xa b c" == ["xa", "b", "c"] /= ["x", "a", "b", "c"] == words "x a b c"

これは、

words = foldr step base

任意のためstepbase

確かに、それがあった場合、

words "xa b c"
= def words and foldr
step 'x' (words "a b c")
= (1)
step 'x' (words " a b c")
= def words and foldr
words "x a b c"

これは矛盾します(2)。

の後、間違いなくいくつかの後処理が必要foldrです。


1
私はこの言語をさらに愛しています...
エンリコマリアデアンジェリス

または["xa"] == words "xa" == step 'x' (words "a") == step 'x' (words " a") == words "x a" == ["x", "a"]、どちらの方向の折りたたみに対しても有効な引数であるという利点があります
Cireo

5

@chiにはwords"a"フォールドを使用して実装できないという素晴らしい議論がありますが、フォールドsを使用すると言っていました

words = filterNull . words1
    where
    filterNull = foldr (\xs -> if null xs then id else (xs:)) []
    words1 = foldr (\c -> if c == ' ' then ([]:) else consHead c) []
    consHead c []       = [[c]]
    consHead c (xs:xss) = (c:xs):xss

最も外側の関数と最も内側の関数の両方がフォールドです。;-)


私はあなたが私が何を意味したか知っていると思いますが、うるさいので+1:P
エンリコマリアデアンジェリス

1

はい。少しトリッキーですが、foldrCPS(継続パススタイル)に慣れている場合は、1つだけを使用してこのジョブを適切に実行できます。私はchunksOf以前、特別な種類の機能を示しました。

この種類のフォールドでは、アキュムレータ、つまりフォールドの結果は関数であり、最終的な結果が得られるように、それを恒等類の入力に適用する必要があります。したがって、ここでは単一の折り畳みを使用しており、そのタイプには関数が含まれているため、これは最終処理段階としてカウントされる場合とそうでない場合があります。議論するためにオープン:)

ws :: String -> [String]
ws str = foldr go sf str $ ""
         where
         sf :: String -> [String]
         sf s = if s == " " then [""] else [s]
         go :: Char -> (String -> [String]) -> (String -> [String])
         go c f = \pc -> let (s:ss) = f [c]
                         in case pc of
                            ""        -> dropWhile (== "") (s:ss)
                            otherwise -> case (pc == " ", s == "") of
                                         (True, False)  -> "":s:ss
                                         (True, True)   -> s:ss
                                         otherwise      -> (pc++s):ss

λ> ws "   a  b    c   "
["a","b","c"]

sf :開始する関数の初期値。

go :イテレーター関数

すべてのターンで前のキャラクターpcと正しいキャラクターの両方がc手元にあるため、実際にはここではCPSの力を十分に活用していません。要素の昇順シーケンスが壊れるたびにchunksOfaをチャンクし[Int][[Int]]いるときに、上記の関数で非常に役に立ちました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.