hi Iftikhar,
this group is more specifically related to question around the use and development of the scalaz library – but, this also aligns with functional programming in Scala more generally, so you may get some useful opinions here.
that forum recommends – and I enthusiastically second the recommendation – to read the fantastic book "Functional Programming in Scala" http://www.manning.com/bjarnason/ which many I know who've read it regard to be one of the finest computing tomes they've ever read.
as to your specific question, I don't think you've got a smell, you simply have chosen one axis of the expression problem, where you have a fixed set of cases (also known as an algebraic data-type) with infinitely extensible behaviour (you can't extends the dataype without breaking clients). If you allow infinite extension of the data-type then you fix the set of allowable behaviours to what is defined in the parent interface (you can't extend without breaking clients).
in OO land you'd need to encode this behaviour in the Visitor pattern (which is pretty horrible). In functional land you have a couple of other options though. For instance, one of the problems with pattern matching is that you cannot guarantee that you you cover all the cases, or that you do not have cases that obscure later cases. For instance:
def bar(x : Foo) = x match {
case A => …
case _ => …
case B => …
case C => …
}
the specific cases for B and C will never trigger because the _ case triggers first. The compiler may be able to help for simple cases like this, but cannot when conditional case logic gets introduced.
An alternate strategy is to use a fold (aka a catamorphism) where you explicitly supply functions for each case, eg:
sealed trait Foo {
def fold[T](a: => T, b: => T, c: => T): T = this match {
case A => a
case B => b
case C => c
}
}
Here, each of these are lazily evaluated (by-name) expressions (the a: => T syntax) and the specific case match causes the right one to be evaluated. In your case you'd call this by:
def somePublicFunction(x : Foo) =
x.fold(
someFunctionSemanticallyRelatedToA(),
someFunctionSemanticallyRelatedToB(),
someFunctionSemanticallyRelatedToC()
)
This makes it impossible by design to accidentally forget to handle one of the cases.
cheers,
jed.