While trying to describe a portion of Sql with Algebraic Data Types in Scala I met a neccessity to create subtraits of the root trait which represents the data type. Since meeting this requirement produced a code that I'm not sure is possible to represent with Haskell's ADTs, and since, in difference to Haskell, ADT is not a native construct to Scala, I am now wondering:
Sql
having a "subtype" Statement
having a constructor Select
in Haskell? (It seems like this may be related).
Here's the model I'm talking about:
sealed trait Sql
sealed trait Statement
extends Sql
sealed case class Union
( left : Statement,
right : Statement )
extends Statement
sealed case class Select
( /** other fields don't matter **/
where : Where )
extends Statement
sealed trait Where
extends Sql
sealed case class And
( left : Where,
right : Where )
extends Where
sealed case class Or
( left : Where,
right : Where )
extends Where
sealed case class Equals
( /** fields don't matter **/ )
extends Where
A composite data type is constructed from other types. The most common composite data types in Haskell are lists and tuples.
What Are Algebraic Data Types? ADTs are commonly used in Scala. Simply put, an algebraic data type is any data that uses the Product or Sum pattern. The question now shifts to understanding what Product and Sum Types are.
You can combine multiple types with an and (for example, a name is a String and another String ), or you can combine types with an or (for example, a Bool is a True data constructor or a False data constructor). Types that are made by combining other types with an and are called product types.
Algebra of ADTs Product types and sum types are collectively called “algebraic” data types because they have algebraic properties similar to normal integers.
1. No, since your root trait is sealed, it is possible to represent the presented hierarchy as ADTs:
data Sql = Statement Statement | Where Where
-- ^ This is the *type* called `Statement`
-- ^ This is the *constructor* called `Statement`
data Statement = Union Statement Statement | Select Where
data Where = And Where Where | Or Where Where | Equals
It is possible in this case, because you are able to enumerate all of the "subclasses" of your data type (Sql
in this case), which makes it possible to convert them into ADT constructors. It is only difficult to emulate type hierarchies as ADTs if you want to allow "constructors"/"sub-classes" to be added arbitrarily by the user.
2. The term ADT is never applicable to Scala code since Scala lacks ADTs in the language. However, the classes that you've presented behave similarly to ADTs, so I'd say "close enough."
3 & 4. The languages have different strengths and weaknesses.
Haskell can emulate every Scala language feature, and Scala can emulate every Haskell feature, since both languages are turing complete, and allow for different levels of meta-programming. Haskell does of course have Template Haskell, which allows for anything to be emulated -- you could probably use TH to be able to write Scala code in a Haskell file and have it be compiled as Haskell.
Objects and inheritance are not needed in Haskell, and ADTs are mostly not needed in Scala, so there's no reason to compare the two. Most object-oriented features can also be emulated with simple Haskell type classes and data types, and using module boundaries. ADTs can be emulated in Scala with case classes, and Haskell type classes can be emulated with implicit parameters and implicit object instances.
However, I'd say that it in general is easier to emulate certain Scala features in Haskell, though, because Haskell allows for more "implicit language extensions" than Scala does. What I mean by that is that if you want to emulate Haskell Monad
s in Scala, you have to write lots of code in the parts that use the Monad
s, while if you want to emulate, let's say, Scala's delimited continuations or implicit parameters in Haskell, you can simply write a Monad
instance (for continuations) or a multi-param type class (for implicit parameters) once for that, and the code that you later write in your actual functions will look very close to the Scala code without much boiler plate. Many if not most of Scala's advanced features do also originate from either Haskell or OCaml, so they are already there and don't need to be translated.
In other words: The complex code required to add the new feature only has to be added in one location in Haskell, after which it can be used in multiple locations very easily, while you often have to add lots of "noise" everywhere in your Scala code if you want to emulate a Haskell feature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With