0

handleReplaceタイプのHaskellに関数があります

handleReplace :: Character -> T.Text -> T.Text

T は、修飾されたインポートとしての Data.Text モジュールです。したがって、この関数は、次のように定義された Character 型を受け取ります。

data Character  = Character (String, String, String, String) [(String,String)] Case String Stringderiving (Read, Show)

およびテキスト値。文字列タプルのリストのみを考慮し、タプルの最初の項目のすべての出現を Data.Text 文字列のタプルの 2 番目の項目に置き換えようとし、そのタプルのリストのすべての要素を置き換えます。1 つの例外は、置換される出現箇所が で始まる単語内にある場合です/。私は次のように関数を定義しました:

handleReplace :: Character -> T.Text -> T.Text
handleReplace (Character _ []   _ _ _)        s = s
handleReplace (Character _ ((a, b):xs) _ _ _) s = handleReplace emptyCharacter string
                                                where emptyCharacter = Character ([], [], [], []) xs Normal [] []
                                                      string         = T.unwords $ map (\ x 
                                                                                         -> if (T.head x) == '/'
                                                                                                then x
                                                                                                else T.replace (T.pack a) (T.pack b) s
                                                                                      ) $ T.words s

残念ながら、それは機能しません。エラーはスローされませんが、期待される出力が得られません。実行時

handleReplace (Character ([],[],[],[]) [("u","U"),("v","wv")] Normal [] []) $ T.pack "/uu v uu vvuu"

私はそれが(明らかにテキスト型として)返されることを期待しています"/uu wv UU wvwvUU"が、ghciでそれを試すと、次のようになります:

"/uu /UU /uu /UU wv UU wvwvUU /UU wv UU wvwvUU /UU wv UU wvwvUU ...

など なぜですか?

4

1 に答える 1

3

さまざまなスコープに 1 文字の変数が多数あると、この種の間違いを犯しやすくなります。あなたが欲しかったのは

else T.replace (T.pack a) (T.pack b) x

それよりも

else T.replace (T.pack a) (T.pack b) s

そうしないと、特定のチャンクではなく、文字列全体に対して置換を何度も実行することになります。この変更により、少なくともテストケースで目的の出力が得られるようです。

余談ですが、こんな感じで書きます。完全にポイントフリーというわけではありませんが、より近く、非常に理解しやすくなっています。

import Control.Arrow ((***))
import qualified Data.Text as T

handleReplace :: Character -> T.Text -> T.Text
handleReplace (Character _ [] _ _ _) = id
handleReplace (Character _ xs _ _ _) = doReplacements $ map (T.pack *** T.pack) xs

doReplacements :: [(T.Text, T.Text)] -> T.Text -> T.Text
doReplacements reps = T.unwords . map replaceAll . T.words
    where replaceAll word = foldl replaceSingle word reps

replaceSingle :: T.Text -> (T.Text, T.Text) -> T.Text
replaceSingle word (inp, out)
    | T.head word == '/' = word
    | otherwise          = T.replace inp out word
于 2013-02-15T15:42:18.040 に答える