1

I didn't know how to describe this for the title, but it should be understandable with the example code. How can I shorten this:

parse qs (e@Mark        :t@(Noun _)    :Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@Mark        :t@(Verb _ _ _):Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Asgn _)    :t@(Noun _)    :Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Asgn _)    :t@(Verb _ _ _):Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@LeftParen   :t@(Noun _)    :Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@LeftParen   :t@(Verb _ _ _):Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Adv _ _)   :t@(Noun _)    :Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Adv _ _)   :t@(Verb _ _ _):Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Verb _ _ _):t@(Noun _)    :Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Verb _ _ _):t@(Verb _ _ _):Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Noun _)    :t@(Noun _)    :Adv _ f:ss) = parse qs $ e : f t : ss
parse qs (e@(Noun _)    :t@(Verb _ _ _):Adv _ f:ss) = parse qs $ e : f t : ss

The list is of type [Token] (as is qs, which is used in other definitions), which is my own type. Is it possible to have a sub-type of Token, covering only Mark, Asgn _, LeftParen, Adv _ _, Verb _ _ _ and Noun _, and pattern-match with that?

Edit: definition of Token:

data Token = (Show, Read a) => Noun a
           | Verb String (Token -> Token) (Token -> Token -> Token)
           | Adv String (Token -> Token) Token
           | Conj String (Token -> Token -> Token) Token
           | Name String
           | Asgn AsgnType
           | Mark
           | LeftParen
           | RightParen
    deriving (Show, Read)
4

2 回答 2

2

您可以编写一些帮助函数来为您处理模式匹配(因为您实际上并没有解构列表的前两个元素),然后使用守卫来检查模式是否匹配。

isStartToken :: Token -> Bool
isStartToken = {- returns True for Mark, Asgn, LeftParen etc -}

isNounOrVerb :: Token -> Bool
isNounOrVerb = {- returns True for Noun and Verb only -}

parse qs (e: t: Adv _ f: ss)
    | isStartToken e && isNounOrVerb t = parse qs (e : f t : ss)
    | otherwise                        = {- whatever comes here -}
于 2013-07-27T12:36:39.487 回答
1

这会更清晰和更短:

parse qs (e@Mark:ss) = parse qs $ appNounVerbAdv ss
parse qs (e@(Asgn _):ss) = parse qs $ appNounVerbAdv ss
parse qs (e@LeftParen:ss) = parse qs $ appNounVerbAdv  ss
parse qs (e@(Adv _ _) :ss) = parse qs $ appNounVerbAdv ss
parse qs (e@(Verb _ _ _):ss) = parse qs $ appNounVerbAdv  ss
parse qs (e@(Noun _)  :ss) = parse qs $ appNounVerbAdv  ss
...

appNounVerbAdv (t@(Noun _):Adv _ f:ss) = f t : ss
appNounVerbAdv (t@(Verb _ _ _):Adv _ f:ss) = f t : ss
appNounVerbAdv _ = error ""

只要您有未使用的参数(如上所示),请尝试按照此模式将您的案例分解为较小的qs函数parse

另外,也许像 FSM 这样更正式的方法可能有助于保持事情的可管理性?

于 2013-07-27T17:10:38.180 回答