> One of the best pieces of advice I ever got re: programming was, "don't write the abstraction until you've written three cases first". This is good advice in the intended way (you will write the abstraction better when you get to it),
I don't think this is good advice in the context of Haskell. Haskell allows some abstractions that aren't just "black boxes" or glorified templates. It's of kind like elementary logic: the more models there are, the fewer proofs there are, and vice versa. Analogously, when you write a more abstract function, there are fewer ways you can manipulate it and thus it is in some sense simpler.
I half agree with you. I think the “abstraction” your parent is talking about would correspond to typeclasses rather than polymorphic functions. That is, I think that this would be a reasonable type for a function even if it is only called once:
Eq a => a -> MyObj a -> Maybe Foo
Whereas I think the following would not be ok (probably even if you had a lot of instances)
class HasFoo o where
getFoo :: Eq a => a -> o -> Maybe Foo
instance HasFoo MyObj where ...
I think the rule should be that one should write the most general code that minimises the entropy/size of the source code. That way one can prefer polymorphic functions (as they need less type-signature entropy and bytes, unless they have loads of constraints, in which case one should consider wrapping those constraints together), while still preferring not making crazy single-instance typeclasses.
I don't think this is good advice in the context of Haskell. Haskell allows some abstractions that aren't just "black boxes" or glorified templates. It's of kind like elementary logic: the more models there are, the fewer proofs there are, and vice versa. Analogously, when you write a more abstract function, there are fewer ways you can manipulate it and thus it is in some sense simpler.