0

I asked this question yesterday and the user @dfeuer advised me, that as a beginner I should not define my own classes. His comment:

Haskell beginners shouldn't define their own classes at all. Learn to define functions, and types, and instances. These are the vast majority of actual Haskell code. As you do this, you'll get a good feel for what makes some classes really useful and others less so. You'll learn what makes some classes easy to use and others full of booby traps. Then when you find a good reason to actually define your own class, you'll go through a slew of bad class designs before you get good enough at it that only most of your attempts go badly. Designing good classes is really hard and rarely necessary.

I am curious, why is defining my own classes usually (for a beginner) a bad idea? What are these "booby traps" and why is it so hard to design good classes?

I thought classes are used to define interfaces to data as I do in OOP. When I write java code, I try to write as much code as possible with abstract classes and especially interfaces, so that when I need to change the data, most of my code remains unchanged and that my methods are highly reusable. Another comment under that question by @Carl suggests, that this is not how classes should be used

Why did you create that class? It feels very weird to me - very much like something that someone used to OOP would do, rather than someone used to Haskell. It has too many parameters, they're connected in what feels like a very ad-hoc manner...

My fear is, that without this OOP use of classes, any change in data would break huge part of code. Is this fear unfunded? And if it is funded, why I should not use classes to define interface to data?

To be fair, I am self taught java programmer and I did not read others people code, so maybe I am doing java wrong also. I only read some books on how the language works and then built an application. I developed it for a year or so, and my whole style is consequence of this experience alone. My style seems to work well for my needs though, and thus I assume it is how java programming/OOP is indeed done.

Enlico
  • 23,259
  • 6
  • 48
  • 102
Umaxo
  • 117
  • 3
  • 4
    This is a great question to be asking, but I think it is pretty opinion-based and open-ended, which makes it not a good fit for Stack Overflow. One thing I can point out at least is that just plain old functions are a great substitute for an "interface". If you give me an `a -> b`, I can't know where it came from - all I know is I call it with an `a` and I get a `b` back. And data types are a good way to compose multiple data objects into a single entity. – amalloy Sep 02 '21 at 05:56
  • Does this answer your question? [Java's Interface and Haskell's type class: differences and similarities?](https://stackoverflow.com/questions/6948166/javas-interface-and-haskells-type-class-differences-and-similarities) Also this [What does instance mean in Haskell?](https://stackoverflow.com/questions/44886668/what-does-instance-mean-in-haskell) – n. m. could be an AI Sep 02 '21 at 06:45
  • @amalloy I do not understand. Plain old functions need to be implemented. Say I want a function that returns me double for some several different types. So I want something like getDouble :: a -> Double. But I have no way of writing that function, because I do not know how to extract Double from unknown type. – Umaxo Sep 02 '21 at 06:54
  • @n.1.8e9-where's-my-sharem. I fail to see relevance of the second link. The first one basically answers my follow up question, if I can interpret the answers as Carl's comment was wrong and one can use typeclasses as interfaces, since typeclasses are more general version of interfaces. However, it does not answer my main question "What are these "booby traps" and why is it so hard to design good classes?" (maybe I shouldn't ask the follow up question, since only one question is supposed to be asked) – Umaxo Sep 02 '21 at 07:07
  • 1
    Consider `map`. It takes as an argument a function of type `a -> b`. In a sense, it asks the outside world abstractly for some way to transform `a`s to `b`s. The *type* of the function is the interface, and the implementation of a function is analogous to an instance or subclass. Likewise, you don't need to know how `map` is implemented: you just interact with it by invoking it, in ways its type signature ("interface") allows. – amalloy Sep 02 '21 at 07:26
  • 1
    @amalloy Ok, so the interface I wanted to do with typeclasses I can just do with adding the "interface function" as the input to the function that makes further processing. That actually makes perfect sense. Am I understanding you right? – Umaxo Sep 02 '21 at 07:28
  • 2
    In Java, you use classes as a fundamental tool for nearly every program, and you use generics a little; in fact it's an advanced feature that was not even in the language at the beginning. In Haskell you use parametric polymorphism (which is what Java calls "generics") a a fundamental tool for nearly every program, and you use classes a little; in fact using classes in the way that Java does requires advanced features that were not even in the language at the beginning! If you lean on OO approaches (classes for everything!) you will make it much harder to learn how typical Haskell code works. – Ben Sep 02 '21 at 07:51
  • "What are these "booby traps" and why is it so hard to design good classes?" is not an answerable question I'm afraid. Not in the format that this site encourages anyway. It is an invitation to an open discussion. – n. m. could be an AI Sep 02 '21 at 07:52
  • Maybe it sheds some light if we compare the usage of type classes/interfaces: `public static > T min (T x, T y)` vs. `min :: Ord a => a -> a -> a` –  Sep 02 '21 at 10:02

1 Answers1

9

I'm a relatively a new (and amateur) Haskell enthusiast.

I'd say: just stop thinking you can reuse OOP knowledge, patterns, and other things in Haskell. Even terminology is not "reusable". Classes are not the same thing in OOP languages vs Haskell (well, they are called typeclasses in Haskell, actually).

This is an answer to a question of mine. It starts more or less like this:

It's true that typeclasses can express what interfaces do in OO languages, but this doesn't always make sense.

i.e. stating the inherent difference between two similar (only apparently similar!) concepts in Haskell vs OOP languages.

Another interesting link is on Design Patterns in Haskell. It is very high level, and I still don't quite understand how some tools can be used in Haskell as an alternative to a specific OOP pattern. (Probably the fact that first-class function remove the need for the strategy pattern is the only thing that is totally clear to me, at the moment.) However, I think it is a good reading and, most of all, it should convince you that learning and coding in Haskell comes with a huge mental shift, and it is best approached by starting from zero. If you refuse that, you're not gonna learn Haskell.

I'm not saying that you shouldn't use your brain to notice similarities between OOP languages and Haskell. You should just assume that even trying to build on those observations will handicap your learning process.

As regards Haskell specifically, sitting down and studying LYAH as you were at school (with a laptop to try out examples) is a good way to learn very well the basics. It is an easy-ish to read book, and guides you by hand.

For what is worth, I think that Structure and Interpretation of Computer Programs is a good book that can accompany learning a functional language, as it gives you a practical background to the shift of philosophy I mentioned earlier. You must do the exercises. Doing them will force you towards that mental shift.

A final suggestion, that I would never apply before studying LYAH thoroughly, is to complete The Monad Challenges. But I have to say that LYAH does already a good job at teaching you what the Challenges ask you to think about. I found myself thinking "I already know this", "why is the challenge going so roundabout?".

Enlico
  • 23,259
  • 6
  • 48
  • 102
  • Thanks for the answer, especially the links. I will go through them. I am actually rebuilding app I have written in java to Haskell, so tendency to use similar solutions is perhaps quite strong. I do not agree with your assessment that using OOP solutions when you do not see "functional" one is a hindrance though. I am learning functional, so how can I use solution I have yet to learn? I do not see how I can get rid of OOP way of solving problems if I do not even know what "functional" way to solve them is. That is why I am learning, but meanwhile have to do with my own clumsy attempts. – Umaxo Sep 02 '21 at 07:33
  • 3
    @Umaxo The point is, you probably should be doing things to learn functional ways of designing code. Like follow tutorials or read books, or something. Rewriting an existing Java app in Haskell is not a good way of doing that. To do so you'll end up forcing yourself to write Haskell code that emulates features of Java, which is *much* more complicated than beginner-level Haskell and also much more complicated than the original Java! Seriously, Haskell is not that hard a language, but OO programmers make it much harder for themselves by applying OO mindsets to a totally different language. – Ben Sep 02 '21 at 07:46
  • _I do not agree with your assessment that using **OOP** solutions when you do not see **"functional"** one is a hindrance though_. Take another example by changing the bold words to C and C++. It's the same pattern of reasoning. But for that I'd suggest to listen to [Kate Gregory](https://www.youtube.com/watch?v=YnWhqhNdYyk). I don't have a similar link for OOP vs Functional, @Ben maybe has one? – Enlico Sep 02 '21 at 07:47
  • @Enlico Sadly, I do not have any experience with C and C++. – Umaxo Sep 02 '21 at 08:27
  • @Ben I do not think I am trying to emulate features of Java. Of course, the similarity between interfaces/typeclasses is quite strong, so naturally I tried that, but the rest of Haskell seems to me not to resemble Java at all. In fact, I started to learn to code only 2 years ago, while I was (almost) a pure mathematician for more than 10 years. I actually find functional concepts much more simpler and natural than OOP concepts, which I usually find too contrived. I also do not think Haskell is hard, I had much harder time to understand Java. – Umaxo Sep 02 '21 at 08:33
  • _the similarity between interfaces/typeclasses is quite strong_ is a statement that assumes a strong knowledge of both. Do you think you have a strong knowledge of Haskell typeclasses, given you call yourself a beginner? – Enlico Sep 02 '21 at 08:35
  • @Enlico ok, let me call it apparent similarity. – Umaxo Sep 02 '21 at 08:37
  • That's the point. The _strong_ similarity is only _apparent_; they're just loosely related. Thinking otherwise will mislead you. But that's just my and (maybe) Ben's opinion. – Enlico Sep 02 '21 at 08:41
  • @Enlico I got that, and I agree. – Umaxo Sep 02 '21 at 08:42
  • 1
    @Umaxo I don't think you're *trying* to emulate features of Java. But if your approach is "I have to use OOP approaches to solving problems because that's what I know", you may accidentally force yourself to. You'll start with the structure of your OO app, and eventually find it very difficult to complete. At that point the only way to move forwards with completing your rewrite is to use advanced Haskell features to sort-of emulate basic Java features that Haskell doesn't have. The "natural" Haskell approaches won't fit the structure you've already started. – Ben Sep 02 '21 at 23:05
  • 1
    @Umaxo So this learning technique won't help you discover easy solutions to those problems in Haskell. It looks easier because you're starting with something you already know, but it's actually **much harder** to "code this app in Haskell the same way Ι would code it in Java" than it is to "code this app in Haskell the way a Haskeller would". There is *more* that is unfamilliar to you that you have to learn in this first exercise than if you start something fresh, not less, and you'll have to learn advanced techniques without knowing the fundamentals they're built on. – Ben Sep 02 '21 at 23:05