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)
1
  • What is the full definition of Token? Commented Jul 27, 2013 at 12:29

2 Answers 2

2

You could write some helper functions that handle the pattern matches for you (since you don't actually deconstruct the first two elements of the list) and then use guards to check if the patterns are matched.

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 -}
Sign up to request clarification or add additional context in comments.

2 Comments

The otherwise case could be a bit difficult, given all my other patterns, but I'll give it a try. I'll mark this as the answer if it works.
Instead of using otherwise like this, you can also start a new equation after parse qs (e : t : Adv _ f : ss) | ... = ....
1

This would be a little clearer and shorter:

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 ""

Just try to break your cases up into smaller functions along this pattern whenever you have an argument that isn't used (as in qs in parse above).

Also maybe a more formal approach like an FSM might help keep things manageable?

2 Comments

In implementing the previous answer, I've tended towards functions more like your appNounVerbAdv. Thanks for confirming that approach.
On the FSM idea, that could work. I'll bear that in mind, and maybe try to rewrite in that style if this one doesn't work out. My main concern is that my program requires reading against the direction of the input stream. I don't know enough about FSMs to know whether they are suited to that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.