Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Haskell missing "obvious" Typeclasses

Consider the Object-Oriented Languages:

Most people coming from an object-oriented programming background, are familiar with the common and intuitive interfaces in various languages that capture the essence of Java's Collection & List interfaces. Collection refers to a collection of objects which doesn't necessarily have an natural ordering/indexing. A List is a collection which has a natural ordering/indexing. These interfaces abstract many library data-structures in Java, as do their equivalent interfaces in other languages, and an intimate understanding of these interfaces are required to work effectively with most library data-structures.

Transition to Haskell:

Haskell has a type-class system which acts on types analogously to interfaces on objects. Haskell seems to have a well designed type-class hierarchy with regard to Functors, Applicative, Monads, etc. when the type regard functionality. They obviously want correct and well-abstracted type-classes. Yet when you look at many Haskell's containers (List,Map,Sequence,Set,Vector) they almost all have very similar (or identical) functions, yet aren't abstracted through type-classes.

Some Examples:

  • null for testing "emptyness"
  • length/size for element count
  • elem/member for set inclusion
  • empty and/or singleton for default construction
  • union for set union
  • (\\)/diff for set difference
  • (!)/(!!) for unsafe indexing (partial function)
  • (!?)/lookup for safe indexing (total function)

If I want to use any of the functions above, but I have imported two or more containers I have to start hiding functions from the imported modules, or explicitly import only the necessary functions from the modules, or qualifying the imported modules. But since all the functions provide the same logical functionality, it just seems like a hassle. If the functions were defined from type-classes, and not separately in each module, the compiler's type inference mechanics could resolve this. It would also make switching underlying containers simple as long as they shared the type-classes (ie: lets just use a Sequence instead of List for better random access efficiency).

Why doesn't Haskell have a Collection and/or Indexable type-class(es) to unify & generalize some of these functions?

like image 836
recursion.ninja Avatar asked Aug 07 '14 20:08

recursion.ninja


People also ask

Is Haskell OO?

Haskell isn't an object-oriented language. All of the functionality built here from scratch already exists in a much more powerful form, using Haskell's type system. Many of the ideas used in this section will come up again, but rather than hacking together objects, you'll be creating types.

Does Haskell have inheritance?

Does Haskell have inheritance? Well, no, it doesn't, because Haskell does not have objects, and inheritance is a relationship between two objects. Objects are a combination of internal state (data) and methods (behavior).

Does Haskell have classes?

Haskell classes are roughly similar to a Java interface. Like an interface declaration, a Haskell class declaration defines a protocol for using an object rather than defining an object itself.


1 Answers

As other answers have pointed out, Haskell tends to use different vocabulary. However, I don't think they've explained the reason for the difference very well.

In a language like Java, functions are not "first class citizens"; it's true that anonymous functions are available in the latest versions, but this style of interface (Collection, Indexable, Interable, etc.) were designed before that.

This makes it tedious to pass our code around, so we prefer other people's data to be passed to our code. For example:

  • Data implementing Java's Iterable lets us write for (Foo x : anIterable) { ... }
  • Data implementing PHP's ArrayAccess lets us write anArrayAccess[anIndex]

This style can also be seen in OO languages which implement generators, since that's another way for us to write for yieldedElement in aGenerator: ....

Haskell takes a different approach with its typeclasses: we prefer our code to be passed to other people's data. Some (simplified) examples:

  • Functors accept our code and apply it to any elements they 'contain'
  • Monads accept our code and apply it in some kind of 'sequence'
  • Foldables accept our code and use it to 'reduce' their contents

Java only needs Iterable since we have to call our code in our for loop, so we can make sure it's called correctly. Haskell requires more specific typeclasses since someone else's code will be calling ours, so we need to specify how it should be called; is it a map, a fold, an unfold, etc.?

Thankfully, the type system helps us choose the right method ;)

like image 168
Warbo Avatar answered Oct 21 '22 00:10

Warbo