1

内部に文字列を含むリストがあり、そのCharをCharごとに分解し、代わりにIntegerとしてリストに入れる必要がありますが、型に悩まされています

私が持っているのは、モナドに読み込むtxtファイルです:

getTxt = do
  y <- readFile "foo.txt"
  return y

fooこれだけが含まれています:

"1234567890\n"

次に、シーケンスに近いと思いましたが、次のリストが表示されます。

["1","2","3","4","5","6","7","8","9","0"] :: [[Char]]

しかし、私は必要[Integer]です。ordかかりますChar -> Intが、どうやってそれを読むのです[Char] -> [Int]か?そして、これらの試行錯誤の末、最終的に最後の新しい行を除外する必要はありませんか?

助言がありますか?

4

4 に答える 4

1

を使用するordと、型は一致しますordが、数値ではなく ascii 値が得られるため、必要なものではありません: ord 5is 53、 not 5. 48 を引いて数字を取得し、その数字をロールアップして 1 つの数字にすることもできますが、ライブラリ関数を使用する方が簡単です。最も簡単な選択はread次のとおりです。

getInt :: IO Integer
getInt = do
    y <- readFile "foo.txt"
    return (read (takeWhile (/='\n') y))

リンクされた回答のように、ここでの最善の解決策はを使用することreadsです。

readsのペアとして可能な一致のリストを見つけ(match,remainingstring)ます。これは、残りの文字列に自動的に改行を残すため、うまく機能します。

*Main> reads "31324542\n" :: [(Integer,String)]
[(31324542,"\n")]

それを使用しましょう:

findInt :: String -> Maybe Integer
findInt xs = case reads xs of              -- have a look at reads xs
    ((anint,rest):anyothers) -> Just anint -- if there's an int at the front of the list, just return it
    _ -> Nothing                           -- otherwise return nothing

Maybeプログラムをクラッシュさせたり、例外処理を行ったりせずに失敗できる便利なデータ型です。 Just 5は出力を得たことを意味し、それは5. Nothing問題があり、出力がないことを意味します。

addTen :: FilePath -> IO ()
addTen filename = do
    y <- readFile filename
    case findInt y of 
       Just i -> putStrLn ("Added 10, got "++show (i+10))
       Nothing -> putStrLn ("Didn't find any integer at the beginning of " ++ filename)

これにより、次のことが得られます。

*Main> addTen "foo.txt"
Added 10, got 1234567890


文字が表す整数だけが必要な場合import Data.Charは、ファイルの先頭に置いて実行できます

ordzero = ord '0'   -- handy constant, 48, to unshift the ascii code to a digit.

getInts :: FilePath -> IO [Int]          -- ord gives the smaller Int, not Integer
getInts filename = do
    y <- readFile filename
    return [ord achar - ordzero | achar <- takeWhile isDigit y]

これは、y数字である限り文字列の文字を取得し、それらを見つけてord、減算ord '0'(48)し'4'4などに変換します.

于 2012-09-28T21:33:00.360 に答える
0

したがって、次のタイプの関数が必要です。

charsToInts :: [Char] -> [Int]

これは、問題をより小さな問題に分解することで解決できます。まず、singleCharを に変換する関数が必要Stringです。

charToString :: Char -> String
charToString c = [c]

...次に、 a を に変換する関数が必要StringですInt:

stringToInt :: String -> Int
stringToInt = read

Char...次に、これら 2 つの関数を構成して、 s をIntsに変換する関数を取得します。

charToInt :: Char -> Int
charToInt = stringToInt . charToString

Charこれで、 を使用してその関数を持ち上げて、 のリスト全体を処理できますmap

charsToInts :: [Char] -> [Int]
charsToInts = map charToInt

...これで完了です。

デモ目的のためだけに、非常に冗長な道をたどりました。私自身のコードでは、通常、これらすべての定義を次のようにインライン化します。

charsToInts :: [Char] -> [Int]
charsToInts = map (read . singleton)
  where singleton x = [x]

コードで使用するstringsToIntsには、次のように記述します。

getTxt :: IO [Int]
getTxt = fmap charsToInts $ readFile "foo.txt"

これはの結果にfmap適用され、上記のコードは次と同等です。charsToIntsreadFile

getTxt = do
    chars <- readFile "foo.txt"
    return $ charsToInts chars

【社外コメント:

リスト内包表記を使用すると、さらに削減できます。

getTxt :: IO [Int]
getTxt = do
    chars <- readFile "foo.txt"
    return [read [d] | d <- chars]

トップレベル関数の型注釈は一般的に良い考えですが、この場合は必須であることに注意してください (関数本体に注釈を入れない限り)。それ以外の場合、「読み取り」は必要なタイプがわからないためです。]

于 2012-09-28T21:43:41.237 に答える
0

mapおよびのドキュメントを参照してfilterください。それは非常に重要です。あなたの場合

integersFromFile :: String -> IO [Int]
integersFromFile filename = map digitToInt <$> readFile filename 
于 2012-09-28T20:11:04.113 に答える
0

あなたの言っていることが理解できるかどうかはわかりませんが、illusionoflife が示唆していると思うことの私のバージョンは、リスト内包表記です...

do cs <- readFile "foo.txt"
   return [ord c | c <- cs, c /= '\n']

これはちょっとしたごまかしです。ファイルには数字とその行末だけが含まれていると想定し、行末文字がどこにあってもそれを取り除くだけです。

説明 - これはリスト内包表記です。はc <- cs基本的にc各キャラクターを順番に割り当てます。c /= '\n'行末でケースを除外します (どこで発生しても - 最後である必要はありません) 。はord c、最終的なリストに含める値を提供します。

filterこれは と を使って表現することもできますがmap、慣れるとリスト内包表記の方がはるかに便利です。

改善されたバージョンでは、 isDigit( Data.Charから) を使用して文字をチェックする場合があります。リストに無効な文字があるかどうかを追跡する方法もあるので、後でそれらのマーカーを確認して報告するか、フィルターで除外できます

于 2012-09-28T20:40:06.543 に答える