将字符串转换为“成绩”列表

时间:2016-04-20 12:22:22

标签: string list haskell

我想创建一个函数,该函数接收不同长度的多个“等级”字符串,并将其转换为成绩列表。

成绩只是一个看起来像这样的数据结构(只是一个任意评分系统):

data Grade = A+ | A | A- | B+ | B | B- | P | F
    deriving (Show, Eq)

如您所见,等级的长度各不相同。如果它们的长度为1或长度一致,那就更容易了。

这是我想要的功能:

这就是字符串输入看起来像"PA+FABA+B-A"

的内容
stringToGrade :: String -> Grade
stringToGrade stringGrade
  | stringGrade == "A+" = A+
  | stringGrade == "A" = A
  -- and so on

extractGrades :: String -> [Grade]
extractGrades stringGrades = case stringGrades of
  [] -> []
  x:y:ys
    | x == "A" && y == "+" -> [stringToGrade (x : y)] : extractGrades ys
    | x == "A" -> [stringToGrade x] : extractGrades y:ys
    -- and so on

正如你所看到的,这不会发生在任何地方。

我有一种优雅而简单的方式来做这件事,而不是编码所有东西吗?

2 个答案:

答案 0 :(得分:4)

我们可以应用模式匹配以匹配字符串前缀。这是一个例子:

foo :: String -> [Int]
foo [] = []
foo ('h':'e':'l':'l':'o':rest) = 1 : foo rest
foo ('b':'o':'b':rest) = 2 : foo rest
foo ('b':rest) = 3 : foo rest
foo _ = error "foo: invalid input syntax"

样本用法:

foo "hellobbobbobhello" ==> [1,3,2,2,1]

答案 1 :(得分:0)

您可以使用拆分功能的组合将字符串拆分为令牌。

split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"

将创建此表单,其中附加了后缀。

["PA+","FABA+","B-","A"]

现在,您可以使用自定义拆分器进一步拆分

splitInit [] = []
splitInit [x] = [[x]]
splitInit [x,y] = [[x,y]]
splitInit (x:xs) = [x] : splitInit xs

组合会给你

concatMap splitInit $ split (keepDelimsR $ oneOf "+-") "PA+FABA+B-A"
["P","A+","F","A","B","A+","B-","A"]

您可以在其中映射构造函数