2016-05-21 11 views
0

:: RawText - > [ワード]与えられた文字列を分割 を単語リストに追加します。Haskellの個々の列に単語の文字列を分割再帰関数

簡潔にするため、生のテキストは、文字と空白の文字列で、不規則な間隔を持つ可能性が高いと想定しています。 例:split "one two three ff" = ["one"、 "two"、 "three"、 "ff"]

["one" ***の例外を取得し続ける:recursion.hs:30 :1-14:関数の非網羅的なパターンが流出したので、再帰は決して終わらないが、基本的なケースがある。

My機能

type RawText = String 
-- [Char] 'a','b','c','d','e' 
type SingleWord = String 
type Line = [SingleWord] 
type Page = [Line] 

--  [-------CHAR-----] 
-- split " one two three ff " = ["one","two","three","ff"] 
--        [char],[char],[char],[char] 
-- " " is delimiter for a [] 

split' :: RawText -> [SingleWord] 
spilt' [] = [] 
split' xs 
    | xs == [] = [] 
    | isBlank (head xs) = split' xs 
    | otherwise = waitForBlank xs : spilt' (tail xs) 

isBlank :: Char -> Bool 
isBlank x = if x == ' ' then True else False 

waitForBlank :: String -> String 
waitForBlank [] = [] 
waitForBlank (x:xs) 
    | isBlank x = [] 
    | otherwise = x : waitForBlank xs 
+1

有効にする警告は「spilt' 'のための署名を逃す」のようなメッセージを生成し、タイプミス' spilt'をスポッティングでここに役立っていると思います。 – chi

答えて

0

私のソリューション(フィードバック歓迎、ここでは初心者)

split' :: RawText -> [SingleWord] 
split' [] = [] 
split' (x:xs) 
    | isBlank x = split' xs 
    | otherwise = waitForBlank (x:xs) : split' (drop (length (waitForBlank (x:xs))) xs) 

isBlank :: Char -> Bool 
isBlank x = if x == ' ' then True else False 

waitForBlank :: String -> String 
waitForBlank [] = [] 
waitForBlank (x:xs) 
    | isBlank x = [] 
    | otherwise = x : waitForBlank xs 
+1

おめでとうございます!この解決策はうまくいくかもしれませんが、明示的な再帰を排除するライブラリ関数を使用することで改善できます(これは多くの関数プログラマにとって不愉快です)。定義済みの関数を使用する方法の例については、私の答えを参照してください。 – ThreeFx

5

あなたは機能split'と機能spilt'を宣言。タイプミスを訂正してください。

split' :: RawText -> [SingleWord] 
spilt' [] = [] -- the first typo is here 
split' xs 
    | xs == [] = [] 
    | isBlank (head xs) = split' xs 
    | otherwise = waitForBlank xs : spilt' (tail xs) -- here is the second typo 

メッセージを説明するために、それはあなたが宣言した2つの異なる機能にコードを分割するのが最善です:あなたはsplit'に再帰するとき

split' :: RawText -> [SingleWord] 
split' xs 
    | xs == [] = [] 
    | isBlank (head xs) = split' xs 
    | otherwise = waitForBlank xs : spilt' (tail xs) 

-- spilt' :: [a] -> [a] (or something like this) 
spilt' [] = [] 

は今、あなたはspilt'を呼び出します。宣言した関数spilt'は空でないリストを処理しないため、例外がスローされます。さらにノートで


、あなたがタイプミスを修正した場合、あなたは二度空のリストを処理する必要はありません。

また
import Prelude hiding (split) 

split :: RawText -> [SingleWord] 
split [] = [] 
split xs 
    -- | xs == [] = [] this case is matched by the pattern 
    --     above and thus not needed 
    | isBlank (head xs) = split' xs 
    | otherwise = waitForBlank xs : split (tail xs) 

、パターンリストに一致したときに、あなたが明示的にパターンマッチすることができます

split [email protected](x:xs) 
    | isBlank x = split' xs 
    | otherwise = waitForBlank s : split' xs 

しかし、どういうわけか、この機能はまだSE:明示的に拳consアプリケーションを書き出すことによってheadとリストのtailに対して、すべての手紙を飛ばすより良い方法がなければならない。何が私たちを助けることができるかを見るライブラリ関数を見てみましょう。あなたはそれらを見つけることができますhere

-- drops letters from RawText while a certain predicate holds 
dropWhile :: (a -> Bool) -> [a] -> [a] 
-- takes letters form RawText while a certain predicate holds 
takeWhile :: (a -> Bool) -> [a] -> [a] 

これらはかなり有望です。我々はまた、すべての非空白文字をスキップしてsplit機能をより効率的に行うことができますdropWhileを使用

waitForBlank xs = takeWhile (not . isBlank) xs 
-- or, pointfree: 
waitForBlank = takeWhile (not . isBlank) 

:今、私たちはとwaitForBlankを書き換えることができます。スペースはdropWhileの部分に含まれており、明示的に削除する必要があることに注意してください。

split :: RawText -> [SingleWord] 
split [] = [] 
split xs = waitForBlank xs : split (dropUntilBlank xs) 

waitForBlank xs = takeWhile (not . isBlank) xs 

dropUntilBlank xs = tail (dropWhile (not . isBlank) xs) 

最後の部分もbreakを使用して組み合わせることができます:

split :: RawText -> [SingleWord] 
split [] = [] 
split xs = word : split' rest 
    where 
     (word, (space:rest)) = break isBlank xs 

この答えは、すべての単語が区切られていることを前提としてい

split :: RawText -> [SingleWord] 
split [] = [] 
split xs = waitForBlank xs : split (dropUntilBlank xs) 

-- With dropUntilBlank defined as 
dropUntilBlank xs = tail (dropWhile (not . isBlank) xs) 

-- without the call of tail, dropUntilBlank would keep the space in between the words: 
dropWhile (not . isBlank) "a word" => " word" 
--    note the extra space: ^^^ 

-- using tail on this now produces the correct word: 
tail (dropWhile (not . isBlank) "a word") = "word" 

は今、結果がきれいに見えます単一のスペース。複数の空白の場合はを書き換えて、 dropWhile isBlankの代わりに tailを置き換えて、複数の空白を除外する必要があります。

+0

お返事ありがとうございます+1 – dijam

関連する問題