我建议您学习使用通用实用程序函数来做到这一点。您在此处需要的两个关键功能:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
. 在关联列表中查找映射 - 用于表示映射或字典的对列表。
concatMap :: (a -> [b]) -> [a] -> [b]
. 这类似于map
,但映射到列表上的函数返回一个列表,结果是连接的 ( concatMap = concat . map
)。
要使用lookup
,您需要将Rule
类型更改为这个更通用的同义词:
type Rule = (Char, String)
还要记住,这String
是 的同义词[Char]
。这意味着concatMap
,当应用于 时String
,将每个字符替换为字符串。现在你的例子可以这样写(我改变了参数顺序):
apply :: [Rule] -> String -> String
apply rules = concatMap (applyChar rules)
-- | Apply the first matching rule to the character.
applyChar :: [Rule] -> Char -> String
applyChar rules c = case lookup c rules of
Nothing -> [c]
Just str -> str
-- EXAMPLE
rules = [ ('X', "HYHY")
, ('Y', "OO") ]
example = apply rules "XYF" -- evaluates to "HYHYOOF"
我更改了参数顺序,apply
因为当参数与结果具有相同类型时,通常有助于将该参数设置为最后一个参数(使链接函数更容易)。
fromMaybe :: a -> Maybe a -> a
我们可以更进一步,通过使用Data.Maybe
模块中的实用函数(fromMaybe default Nothing
= default
,fromMaybe default (Just x)
= )将其变成单线x
:
import Data.Maybe
apply rules = concatMap (\c -> fromMaybe [c] $ lookup c rules)
您可以做一个补充练习,即自己手动编写所有这些实用函数的版本:lookup
、concatMap
(将其分解为concat :: [[a]] -> [a]
和map :: (a -> b) -> [a] -> [b]
)和fromMaybe
。这样您就可以理解此解决方案中涉及的“全栈”。