haskell 函数

u7up0aaq  于 2022-11-14  发布在  其他
关注(0)|答案(3)|浏览(170)

我需要创建一个接受字符串和解码规则的函数。它应该改变字符串中的字符,直到根据解码规则没有任何可能的改变。每次我得到字符串和解码规则(第一是什么改变,第二是什么)。
我很迷茫,我试着创建所有可能的组合,然后根据规则生成列表。下面是我的尝试。

rules = [('E',"GZ"),('F',"HK"),('C',"EF"),('J',"CC")]
string = "JCEJ"

combinations = [(x,y,z) | x <- [ch | ch <- string], y <- [x | (x,y) <- rules], z <- [y | (x,y) <- rules]]

generate = [z | (x,y,z) <- combinations, if x == y then z else x]

错误消息:

decoder.hs:8:57: error:
    • Couldn't match expected type ‘Bool’ with actual type ‘[Char]’
    • In the expression: z
      In the expression: if x == y then z else x
      In a stmt of a list comprehension: if x == y then z else x
  |
8 | generate = [z | (x,y,z) <- combinations, if x == y then z else x]
  |                                                         ^

decoder.hs:8:64: error:
    • Couldn't match expected type ‘Bool’ with actual type ‘Char’
    • In the expression: x
      In the expression: if x == y then z else x
      In a stmt of a list comprehension: if x == y then z else x
  |
8 | generate = [z | (x,y,z) <- combinations, if x == y then z else x]
  |                                                                ^
bnl4lu3b

bnl4lu3b1#

  • 免责声明:这一切都没有想象中那么美好。

你有一个rules的查找表,Haskell有一个方便的lookup函数:

ghci> :t lookup
lookup :: Eq a => a -> [(a, b)] -> Maybe b

我们可以在字符串上折叠查找:

ghci> foldr (\x i -> case lookup x rules of {Just s -> s ++ i; _ -> (x:i)}) "" "EF"
"GZHK"

我们将其命名为singlePassDecode

singlePassDecode :: Foldable t => t Char -> [(Char, [Char])] -> [Char]
singlePassDecode s rules = foldr update "" s
  where
    update ch acc = 
      case lookup ch rules of
        Just s' -> s' ++ acc
        Nothing -> ch : ""

但是,一次传递并不一定就能完成任务,我们需要递归调用它,直到没有转换需要执行为止,这意味着我们需要知道输入字符串中是否有字符在查找表中。
剩下的...由正确的递归调用填充,以避免给出完整的答案。

decode :: [Char] -> [(Char, [Char])] -> [Char]
decode s rules
  | any (\ch -> elem ch (map fst rules)) s = ...
  | otherwise = s

第一个条件也可以表达如下。

any (flip elem $ map fst rules) s
kzmpq1sx

kzmpq1sx2#

StringChar的列表,因此[ch | ch <- string]不是必需的。
这里我们用x定义了一些内部列表解析,但是x是一个更具有局部作用域的变量,而不是x <- [ ch | ch <- str]中的x那样的x
你可以让一个过滤条件来过滤,这样:

generate = concat [ y | x <- string, (x', y) <- rules, … ]

这里的是您需要填写的部分。它需要将xx'进行比较。

wfauudbj

wfauudbj3#

规则列表描述了从一个Char到两个Char(如果有匹配)或一个Char(如果没有匹配,则为原始输入)的Map。我们可以通过总是返回一个[Char]来处理这两种情况,并且我们可以泛化到任何a,而不是特定于Char

import Data.Maybe (fromMaybe)

transform :: Eq a => [(a, [a])] -> a -> [a]
transform rules x = fromMaybe [x] (lookup x rules)

由于这种Map不依赖于其他上下文,因此concatMap(也拼写为(>>=))是一个很好的工具,可以将其应用于输入列表并连接结果。

transformAll :: Eq a => [(a, [a])] -> [a] -> [a]
transformAll rules = concatMap (transform rules)
-- or, transformAll = concatMap . transform

如果有一个函数可以重复应用一个函数,直到它不产生任何变化,那么它也会很有用:

fixPoint :: Eq a => (a -> a) -> a -> a
fixPoint f x | x == x' = x
             | otherwise = fixPoint f x'
  where x' = f x

然后,剩下的就是将我们的工具组合在一起:

transformStringRepeatedly :: Eq a => [(a, [a])] -> [a] -> [a]
transformStringRepeatedly rules = fixPoint (transformAll rules)
-- or, transformStringRepeatedly = fixPoint . transformAll

main = print (transformStringRepeatedly [('E',"GZ"),('F',"HK"),('C',"EF"),('J',"CC")] "JCEJ")

我们可以看到,它产生了你所期望的答案:

$ runghc tmp.hs
"GZHKGZHKGZHKGZGZHKGZHK"

相关问题