如何用许多等价模式缩短Haskell函数定义
我不知道如何在标题中描述它,但是使用示例代码应该可以理解。我如何缩短此时间:如何用许多等价模式缩短Haskell函数定义,haskell,pattern-matching,Haskell,Pattern Matching,我不知道如何在标题中描述它,但是使用示例代码应该可以理解。我如何缩短此时间: 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) = p
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
该列表的类型为[Token]
(与其他定义中使用的qs
),这是我自己的类型。是否可以有一个子类型的标记
,只覆盖标记
,Asgn
,左对齐
,Adv
,动词
和名词
,并且模式与之匹配
编辑:标记的定义
:
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)
您可以编写一些帮助函数来为您处理模式匹配(因为您实际上没有解构列表的前两个元素),然后使用卫士检查模式是否匹配
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 -}
这将更加清晰和简短:
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 ""
只要有一个未使用的参数(如上面的parse
中的qs
中),就可以尝试按照此模式将案例分解为更小的函数
另外,也许像FSM这样更正式的方法可能有助于保持事情的可管理性?令牌的完整定义是什么?
否则的情况可能有点困难,考虑到我的所有其他模式,但我会尝试一下。如果有效的话,我会把它标记为答案。不要像这样使用否则
,你也可以在解析qs(e:t:Adv f:ss)|之后开始一个新的等式代码>。在实现上一个答案时,我倾向于使用更像appNounVerbAdv
的函数。谢谢你证实了这一点。在FSM的想法上,这是可行的。我会记住这一点,如果这一条行不通的话,也许会尝试用那种风格重写。我主要关心的是,我的程序要求读取与输入流方向相反的内容。我对FSM了解不够,不知道它们是否适合这样做。