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 字符串中元组中的第二项替换元组中第一项的每次出现,以及该元组列表中的每个元素。一个例外是,如果要替换的匹配项位于以 开头的单词内/。我这样定义函数:

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"(显然是 Text 类型)但是当我在 ghci 中尝试时,我得到:

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

等等 为什么?

4

1 回答 1

3

在不同的范围内有很多单字母变量很容易犯这种错误。我怀疑你想要的是

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 回答