From 32617b053c8511b5914344ed7e7586ec3e11380f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20Garay?= Date: Tue, 6 May 2025 09:48:43 -0300 Subject: [PATCH] Update elixir resources and add new elixir project --- README.md | 24 ++++++++++----- src/elixir_project_forth.md | 26 ++++++++++++++++ src/immutable_data.md | 60 ------------------------------------- 3 files changed, 42 insertions(+), 68 deletions(-) create mode 100644 src/elixir_project_forth.md delete mode 100644 src/immutable_data.md diff --git a/README.md b/README.md index 7ee5ee9..d6134aa 100644 --- a/README.md +++ b/README.md @@ -617,11 +617,22 @@ You can find the instructions [here](https://developer.1password.com/docs/ssh/gi - [Erlang workshop](https://github.com/lambdaclass/erlang_workshop) **Elixir** +- Read the entire `Getting started` section starting at [the introduction](https://elixir-lang.org/getting-started/introduction.html) EXCEPT: + - "Module attributes" + - "Protocols" + - "Sigils" + - "Writing documentation" + - "Optional syntax cheatsheet" + - "Erlang Libraries" + +In addition, read: +- the documentation for Mix (https://hexdocs.pm/mix/Mix.html) +- the documentation for ExUnit (https://hexdocs.pm/ex_unit/ExUnit.html + +Other useful resources: +- "Programming Elixir" by Dave Thomas - [Learning Functional Programming With Elixir](https://pragprog.com/titles/cdc-elixir/learn-functional-programming-with-elixir/) - - Must read: Chapter 1. - - Recommended to read: Chapters 3, 4, 5. -- [Elixir getting started](https://elixir-lang.org/getting-started/introduction.html) -- [Immutable Data](src/immutable_data.md) + - Recommended reading: Chapters 3, 4, 5. - [StreamData: Property-based testing and data generation](https://elixir-lang.org/blog/2017/10/31/stream-data-property-based-testing-and-data-generation-for-elixir/) #### Phoenix @@ -640,10 +651,7 @@ You can find the instructions [here](https://developer.1password.com/docs/ssh/gi - If `asdf` doesn't let you install a previous version of Erlang [this](https://github.com/asdf-vm/asdf-erlang/issues/221) might help. #### Projects -- [Phoenix live counter](https://github.com/dwyl/phoenix-liveview-counter-tutorial) -- [Phoenix todo-list](https://github.com/dwyl/phoenix-todo-list-tutorial) -- [Phoenix ecto encryption](https://github.com/dwyl/phoenix-ecto-encryption-example) -- [Phoenix append-only log](https://github.com/dwyl/phoenix-ecto-append-only-log-example) +Check out the [project description](src/elixir_project_forth.md) #### OpenAPI The OpenAPI Specification (OAS) defines a standard, programming language-agnostic interface description for HTTP APIs, which allows both humans and computers to discover and understand the capabilities of a service without requiring access to source code, additional documentation, or inspection of network traffic. diff --git a/src/elixir_project_forth.md b/src/elixir_project_forth.md new file mode 100644 index 0000000..044838f --- /dev/null +++ b/src/elixir_project_forth.md @@ -0,0 +1,26 @@ +# Elixir Project: Forth + +Implement an evaluator for a very simple subset of Forth. + +[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) is a stack-based programming language. +Implement a very basic evaluator for a small subset of Forth. + +## Requirements: + +### 1: Core language +Your evaluator has to support the following words: +- `+`, `-`, `*`, `/` (integer arithmetic) +- `DUP`, `DROP`, `SWAP`, `OVER` (stack manipulation) + +Your evaluator also has to support defining new words using the customary syntax: `: word-name definition ;`. + +To keep things simple the only data type you need to support is signed integers of at least 16 bits size. + +### 2: User interface + +The evaluator must also be available via a web interface served by Phoenix Liveview. +The user interface features must include: +- uploading a forth program +- requesting an evaluation +- showing the results +- a history of evaluated programs diff --git a/src/immutable_data.md b/src/immutable_data.md deleted file mode 100644 index c1f3dfe..0000000 --- a/src/immutable_data.md +++ /dev/null @@ -1,60 +0,0 @@ -# Immutable data - -Functional languages often work with immutable data (there are people on the Internet who call it *stateless data*), unlike the more classical languages (Procedural/OOP). Mostly, in OOP, data is constantly mutable. In Functional Programming, a function receives some data and returns new data, for practical purposes, without modifying the previous version! This usually saves you from unexpected side effects, being side effects state changes of, for example, some non-local variable. - -## Examples - -In Python we can do this safely: - -```python ->>> a = [1,2,3,4] ->>> def do_something_with_a(): -... a.pop() ->>> def do_something_with_a_even_worse(b): -... b.append(55) ->>> do_something_with_a() ->>> do_something_with_a_even_worse(a) ->>> a -[1, 2, 55] -``` - -In Elixir, this could not happen: - -```elixir -iex(5)> a = [1,2,3,4] -[1, 2, 3, 4] -iex(6)> func = fn -> [1 | a] end -#Function<45.79398840/0 in :erl_eval.expr/5> -iex(7)> func.() -[1, 1, 2, 3, 4] -iex(8)> a -[1, 2, 3, 4] -iex(9)> -``` - -In other languages, more far-fetched examples appear. One thing we often read from people who code in Ruby on Rails is that the framework has thousands of side effects, and often knowing what happens to a variable is hard to follow. -All of this doesn't imply that functional languages don't have a way of handling side effects, they have their special mechanisms: Haskell has Monads, Elixir has Processes. - -We can repeat the example from Python in Elixir, using an Agent: -```elixir -iex(9)> {:ok, mutable_data} = Agent.start_link fn -> [1,2,3,4] end -{:ok, #PID<0.116.0>} -iex(10)> do_something_with_a = fn a -> a ++ [44] end -#Function<44.79398840/1 in :erl_eval.expr/5> -iex(11)> Agent.update(mutable_data, fn a -> a ++ [44] end) -:ok -iex(12)> Agent.get(mutable_data, fn a -> a end) -[1, 2, 3, 4, 44] -``` - -## Concurrency - -Now, note that since data is immutable by default, this facilitates concurrency! There is no need to worry about in-memory state changes, as a functional language will always preserve previous copies of the data you are working with. If we want to parallelize the Python example, we're going to have to make sure that memory access is in the order you're looking for, or we might end up with something inconsistent, involving a lot of headaches :sweat_smile:. Elixir, being immutable by default, does not suffer from this. - -## Old copies - -We imagine one question that might arise when one reads *"functional preserves earlier copies"* is that there are no references, and everything is passed as a copy. But no, that's not the case. In particular, Elixir uses something known as [persistent data structures](https://en.wikipedia.org/wiki/Persistent_data_structure). They're data structures that preserve their "ancestors". - -A very simple example is the simply linked list. If we have `[1,2,3,4]`, we can add it a `0`, then: `[0,1,2,3,4]`. The previous version still exists, just take the tail of the "new" list. This idea extends to all data structures in Elixir. - - Ritch Hickey has a very good talk about this, highly recommended: https://www.youtube.com/watch?v=wASCH_gPnDw \ No newline at end of file