Qqwy
Because of popular demand, and because I’ll probably be busy the next couple of days, so it would need to wait a lot longer if I didn’t publish it now, here it is:
FunLand: This is a package that adds a couple behavours to your Elixir application, which you can use to define Algebraic Data Types.
What exactly are Algebraic Data Types?
They are basically containers for simpler types, in all kinds and shapes.
Some common examples are:
- Lists (as use already every day in Elixir)
- Tuples
- Trees
- Maybe, which either contains a single value or nothing. This allows for propagation of failures in more complex operations.
- Writers, which allow you to keep track of something (such as a log) in the background while passing it through multiple operations that work on simple values.
Why are Algebraic Data Types useful?
Algebraic Data Types are useful in the same way that using loops is useful: They let you re-use a set of operations you already had on a much larger set of inputs/problems.
For instance, Mappable.map lets you re-use any function that works on a single simple type, to tranform the contents of a collection of things of that type:
Mappable.map(input, fn x -> x*2 end) would transform the list [1,2,3] into the list [2,4,6], the tuple {3,1,4} into {6,2,8}, Maybe.just(6) into Maybe.just(12), etc.
This pre-release of FunLand is mainly because I would like some feedback, and to find out if the design choices I have made so far are sound. To implement Abstract Data Types turned out to be a larger endeavour than I had expected. I hope that FunLand will be able to explain to newcomers how ADTs work and why they are useful, and make it easy for people to define their own.
also, Pull Requests are very welcome! ![]()
Sincerely,
~Wiebe-Marten/Qqwy
Trending in Announcing
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #ai
- #elixirconf-us
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
OvermindDL1
Been waiting for this. ^.^
EDIT: Going to add an Either/Result that has a left or right type? Usually used in the same vein as Maybe but usually as return values to hold either a success value and result or an error value and reason (equiv to the usual
{:ok, something}/{:error, reason}) with the usual map and such helpers on them as well?Qqwy
Yes, as you can see on the Roadmap (but please do tell if it isn’t clear enough), Either/Result is on there.
OvermindDL1
Ah, I did see it but I glossed over it as it looked like a function that took two maybe’s and returned the first that was set. Either/Result should not be two things with possible states but rather two possible things. The difference between
Either(Maybe a, Maybe b)andEither(a or b)I guess?Qqwy
@OvermindDL1: You’re right. I dug a bit deeper into the source of Haskell et al, and now I finally understand what Either actually is. It is similar to Maybe, with the difference that the fallback(error, null, etc) value is not static ‘nothing’, but could be anything you like, so you have more information on e.g. at what place something went away from the happy path.
I have released version 0.6 which includes Either. I am not entirely certain about the name Either, though, since I find it somewhat unclear from the name that ‘left’ is thought of as the fallback answer.
I believe that Scala uses ‘Option’ and some other languages use ‘Result’, but these also seem somewhat vague. I am still looking for a better name.
NobbZ
I can’t speak for Scala, but for Rust I can tell that
Result<A, B>is similar to HaskellsEither a b, while RustsOption<A>is similar to HaskellsMaybe a.Also even if often done like this, I wouldn’t say that
Eitheris to signal value or error, but signals the possible outcome of a computation. Consider\n -> if n >= 0 then Right n else Left (-n)(Haskell). This example is somewhat constructed but shows that Either is not always about an error.Thats the reason why there is (in Rust at least) often an additional
Error<A>/Error awhich does alias to some accordingEither String a.Also, even if it is common and idiomatic to use
Rightfor success, this is not necessarily true for every language! Idris does useEitherthe other way round and usesLeftfor success (its not common though to useMaybeorEitherthough).Qqwy
@NobbZ thank you very much! I am relatively new to algebraic data types myself, and FunLand is created mostly to make it clear to newcomers what these things are. Feedback like this is greatly appreciated.
OvermindDL1
Yeah I’ve used both Result and Maybe in the same language, where Maybe is basically a 2-element union (actual union types are better, and if the language has actual union types like elm then there is no maybe), and Result is basically the same thing but its two types are usually
Ok(right) andErr(left).NobbZ
You describe ADTs as
Containersfor some other types, thats not the only truth. ADTs are much more complex.When introducing ADTs I’d do roughly the following order:
data Bool = False | Trueordata Fruits = Apple | Peach | Orange.data Person = Person String Date.data NPC = Monster String Int | Merchant String [(Item, Int)].data Maybe a = Just a | Nothingand explain that this is an extension to the former ones.ADT itself are not necessary to define classes (Haskell term) or interfaces (Idris term) since they are very similar to what the OO-World does call an interface ever since.
As you can see, ADT is more or less an abstraction of what the C world does know as 3 separate concepts:
enum,struct, and (tagged)union.NobbZ
Can you please elaborate what you mean by “union types are better”?
Also when I compile my stuff to something baremetal, I’d be glad if
Maybewould get compiled to some pointer type, whereNothingis represented asNULL. This is called a “zero-cost abstraction”, a buzzword that has been more or less introduced by the Mozilla Foundation and RustOvermindDL1
Well in Elm parlance (since that is what I’ve been doing a lot lately and its syntax is stuck in my head), a Either can only represent two values, which might be fine, however left/right is… not descriptive either (Elm has Maybe on javascript represented as null or the value). Compared to a Union type:
Then just use it as
ImAString "test"orImAnInt 42. That is far more descriptive than something likeLeft "test"orRight 42. You could implement Either in the union types, or you could implement Result (and in fact Elm does implement Result like this):And you use it like:
Proper Tagged Union Types can build up any of those others with ease. I really wish Elixir had a form of Tagged Union types built in, could be done as something like:
So imagine defunion being a macro, takes a union name and a do body, the body defines a set of types that the union could be along with names, typespecs, and an optional when clause of what they store. Internally it would just be represented as a normal erlang tagged tuple, so doing something like
UnionName.MyType("string", 42)would just return{UnionName.MyType, {"string", 42}}or so. The constructors verify the types are correct and the constraints if any provided. You could then do something like a specialunioncaseor so:And so
awould be{:anothertype, 42}in this case. However the important bit would be thatunioncasewouldrequirethe union, access it at compile-time to find out what makes it up, and make sure that all cases are covered, so something like this:Should cause a compile-time warning/error about not all union cases are covered, missing the ‘MoreType’ case, or something like:
And this would cause a warning/error about something like not all union cases are covered, AnotherType is not covered from i>=3 and i<=100 or so. Of course a
_ ->would cover everything./me is a huge proponant of good type systems, the only real thing that Erlang is missing for me, the number of times the lack of a type system bites my butt is far far far more than it would take me time to fix the issues to start with by a type system yelling at me.