2012-03-28 21 views
3

数週間前にハスケルで論文を開始し、最初の割り当てを受けました。私は宿題に関する質問が好きではないことを知っているので、それをどうやって行うのか尋ねるつもりはありません。代わりに誰かが私にこれを正しい方向に押し付けることができれば非常に感謝しています。それは特定の質問ではないかもしれないので、ディスカッション/コミュニティウィキでもっと適切でしょうか?Haskell Assignment - 文字列を単語に分割するのに必要な方向

質問:「Hello、World!」という文字列をトークン化します。 - > ["Hello"、 "World"]

Javaのバックグラウンドから来ているので、これについては通常の方法についてすべてを忘れてしまいます。問題は、私がまだハスケルにとって非常に無知だということです。これは私が思いついたものです:

module Main where 

main :: IO() 
main = do putStrLn "Type in a string:\n" 
      x <- getLine 
      putStrLn "The string entered was:" 
      putStrLn x 
      putStrLn "\n" 
      print (tokenize x) 

tokenize :: String -> [String] 
tokenize [] = [] 
tokenize l = token l ++ tokenize l 

token :: String -> String 
token [] = [] 
token l = takeWhile (isAlphaNum) l 

最初の目に見える間違いは何ですか? ありがとうございます。

+5

スタックオーバーフローがいる限り、あなたも、それらを適切にタグ付けし、あなたがしようとしているかを示す(そしてそれは努力であるとして、宿題の質問のように行います誤っている場合)。これは大丈夫です。 –

+3

あなたがJavaのバックグラウンドから忘れていないことの1つは、変数がHaskellで不変であることです。 'token l 'が' l'を修正すると期待しているようです。ならない。 –

答えて

8

最初の明白な間違いは

tokenize l = token l ++ tokenize l 

(++) :: [a] -> [a] -> [a]同じタイプの2つのリストを追加しています。 token :: String -> String(およびtype String = [Char])以降、その行から推測されるtokenizeのタイプはtokenize :: String -> Stringです。 ここに(:) :: a -> [a] -> [a]を使用してください。

その次の間違いは、再帰呼び出しでは同じ入力をlにもう一度渡すので、無限の再帰があり、常に変更なしで同じことをします。再帰呼び出しへの引数の入力から最初のトークン(およびもう少し)を削除する必要があります。

もう1つの問題は、tokenが入力が英数字で始まると仮定していることです。

また、tokenに渡す条件を確実にする関数が必要です。

+0

朝にこれに戻ってきます。午前2時はいいです。 +1。 – rtheunissen

4

無限のリストで、このラインの結果(Haskellは怠惰であることから、OKですので、リストには、唯一の「オンデマンド」構築されます)、それは引数に変化はないと繰り返しているので:

tokenize l = token l ++ tokenize l 

私たちは、トークン化は次のように呼び出されたときに何が起こっているのかを可視化することができます。この出来事を停止するには

tokenize l = token l ++ tokenize l 
      = token l ++ (token l ++ tokenize l) 
      = token l ++ (token l ++ (token l ++ tokenize l)) 
      = ... 

、あなたはそれが賢明再発するようtokenizeに何の引数を変更する必要があります。

tokenize l = token l ++ tokenize <something goes here> 
+0

再帰呼び出しの前に 'l + 1'から 'トークンの長さを' '落とす'とすれば動作しますか? – rtheunissen

1

これには、パーサーのモナドに似た感じのものがあります。しかし、あなたがハスケルの新人であるように、モナドの構文解析がどのように機能するか(またはあなたのコード内でそれらを使うか)を理解する立場にいることはまずありません。あなたの基礎を与えるために、あなたが望むものを考えてみます。

tokenize :: String -> [String] 

これは、より多くの作品の中にそれをchompし、文字列を取り、入力文字列内の単語に対応する文字列のリストを生成します。これをどのように表現すればよいでしょうか?私たちがしたいことは、単一の文字列を処理する関数を見つけて、空白の最初の記号でその文字列を一連の単語に追加することです。しかし、そしてを残しておく必要があります。 (すなわち、、文字列の残りの部分は)たとえば、あなたがトークン化したいとしましょう:。

茶色のキツネは「」とし、「茶色のキツネが飛び込んだ」処理を続行あなたが最初に引き出す

を跳びました(2番目の文字列の先頭のスペースに注意してください)。これは再帰的に行います。自然に再帰的な関数が必要になります。

自然な解決方法は、を蓄積することです。これまでにトークン化した文字列のセットは、空白にヒットするまで続けてください。現在の文字列(これは、あなたが大抵のことを思いついている実装につながり、時には物を逆転させる)。

2

あなたの間違いをすでに指摘している人もいますが、ちょっとしたヒント:既に役に立つ便利なtakeWhileが見つかったのですが、spanをご覧ください。

-1

あなたのエクササイズはちょっと難しいようでしたので、私はセルフトレーニングのためにそれを解決することに決めました。ここに私が思い付いたものです:

import Data.List 
import Data.Maybe 

splitByAnyOf yss xs = 
    foldr (\ys acc -> concat $ map (splitBy ys) acc) [xs] yss 

splitBy ys xs = 
    case (precedingElements ys xs, succeedingElements ys xs) of 
    (Just "", Just s) -> splitBy ys s 
    (Just p, Just "") -> [p] 
    (Just p, Just s) -> p : splitBy ys s 
    otherwise -> [xs] 

succeedingElements ys xs = 
    fromMaybe Nothing . find isJust $ map (stripPrefix ys) $ tails xs 

precedingElements ys xs = 
    fromMaybe Nothing . find isJust $ map (stripSuffix ys) $ inits xs 
    where 
    stripSuffix ys xs = 
     if ys `isSuffixOf` xs then Just $ take (length xs - length ys) xs 
     else Nothing 

main = do 
    print $ splitBy "!" "Hello, World!" 
    print $ splitBy ", " "Hello, World!" 
    print $ splitByAnyOf [", ", "!"] "Hello, World!" 

出力:

["Hello, World"] 
["Hello","World!"] 
["Hello","World"] 
+1

練習問題は宿題としてタグ付けされていますのでご注意ください! – is7s

関連する問題