Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何用许多等价模式缩短Haskell函数定义_Haskell_Pattern Matching - Fatal编程技术网

如何用许多等价模式缩短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了解不够,不知道它们是否适合这样做。