2

I want to have this nice, clean way to describe an object's properties with functions and pattern matching:

data Animal = Cat | Dog | Cow

isBig :: Animal -> Bool
isLoyal :: Animal -> Bool
-- many more possible properties, including complicated non-bools, methods, and whatnot


--- Describing Cat

isBig Cat = False
isLoyal Cat = False
--- more properties


--- Describing Dog

isBig Dog = False
isLoyal Dog = True
--- more properties


--- Describing Cow

isBig Cow = True
isLoyal Cow = False
--- more properties

However, this gives an error about multiple declarations. Because, apparently, function definition via pattern-matching must be done in consecutive lines.

Is it indicative that my approach is wrong, un-Haskell-like? Or is it just a flaw in the language? Or do I misunderstand something?

1
  • 1
    In this case it doesn't make sense -- or I would have mentioned it in my answer -- but perhaps the case in your question is a simplification of what you are actually trying to do. If so, you could consider making a typeclass that contains isBig, isLoyal, and so on, and making types Dog, Cat, and Cow which implement this class. This is pretty different, though: classes are open, unlike types. Commented Dec 12, 2016 at 18:48

2 Answers 2

5

It is neither a flaw in the language nor an indication that your approach is wrong. It is merely a syntactic restriction put in place as part of a nasty design decision that had to be made one way or another.

The attraction of the restriction is that it means that when reading code, one doesn't need to fear that they have missed part of the definition of a value because it is spread out far across the current file. It does prevent some perfectly logical ways of organizing code, though, including the one you're currently trying to use.

What a shame that we can't have both!

One could consider doing something like this:

data Stats = Stats
    { isBig :: Bool
    , isLoyal :: Bool
    , -- ...
    }

stats :: Animal -> Stats
stats Cat = Stats
    { isBig = False
    , isLoyal = False
    }
Sign up to request clarification or add additional context in comments.

4 Comments

What would be a good way to organize a piece of code like that example, then?
@user2649762 I have added a thought on one approach you might like.
Thanks, one more thing. There are a lot of properties, and most of them aren't defined for all Animals. I had something like 'isLoyal _ = False; isBig _ = False" at the end of the file, so that if I didn't define a particular property for an Animal, it just defaults to a value. How to implement this with your approach?
@user2649762 def = Stats { isLoyal = False }; stats Cat = def { isBig = False }
2

Quoting Section 4.4.3.1 of the Haskell Report:

4.4.3.1 Function bindings

A function binding binds a variable to a function value. The general form of a function binding for variable x is:

[Specification for the syntax of function bindings, covering the multiple clause scenario.]

Note that all clauses defining a function must be contiguous, and the number of patterns in each clause must be the same. [...]

The restriction you have noted is that "all clauses defining a function must be contiguous". Daniel Wagner's answer discusses the presumable rationale behind this design decision. I would, in particular, emphasise that forgetting a clause corresponding to one of the constructors of a type is a quite dangerous mistake that would be easier to commit if it was possible to break apart the clauses in the way you suggest (a function that takes an Animal is expected to handle all three possibilities).

Comments

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.