functional programming
Table of Contents
- 1. functional programming
- 1.1. Monads
- 1.2. Conceptos
- 1.2.1. https://en.wikipedia.org/wiki/Memoization
- 1.2.2. Funciones honestas/transparentes en vez de funciones puras
- 1.2.3. Combinators
- 1.2.4. Idempotent
- 1.2.5. Models of computation
- 1.2.6. Types of evaluation
- 1.2.7. Universal Search Algorithm
- 1.2.8. Parallel evaluation, Cynefin, and Computer Science
- 1.2.9. Constraint programming
- 1.3. Lisp Goodness
- 1.3.1. https://sites.google.com/site/steveyegge2/tour-de-babel
- 1.3.2. https://michaelnielsen.org/ddi/lisp-as-the-maxwells-equations-of-software/
- 1.3.3. http://www.paulgraham.com/onlisp.html
- 1.3.4. https://paulgraham.com/lisp.html
- 1.3.5. How Lisp Became God’s Own Programming Language
- 1.3.6. Greenspun’s tenth rule - Wikipedia
- 1.3.7. Reification (computer science) - Wikipedia
- 1.3.8. Little LISPer, The Seasoned Schemer & The Little Schemer
- 1.4. Homoiconicity - Wikipedia
- 1.5. Pros and cons of fluent interfaces / method chaining / Pointfree style / Tacit programming
- 1.6. Rewriting / Refactorization
- 1.7. Avoid shared mutable state
- 1.8. Replicated Data Types as composable types
- 1.9. Climbing Mount Effect
- 1.10. What’s Functional Programming All About?
- 1.11. Functional semantics in imperative clothing
- 1.12. Effects and CoEffects
- 1.13. SMC: The State Machine Compiler
- 1.14. jrsinclair process
- 1.14.1. What if the team hates my functional code?
- 1.14.2. What’s so great about functional programming anyway?
- 1.14.3. Things I wish someone had explained about functional programming
- 1.14.3.1. Algebraic Structures: Things I wish someone had explained about functional programming
- 1.14.3.2. Type Classes: Things I wish someone had explained about functional programming
- 1.14.3.3. Algebraic Data Types: Things I wish someone had explained about functional programming
- 1.14.3.4. fantasyland/fantasy-land: Specification for interoperability of common algebraic structures in JavaScript
- 1.14.3.5. Fantas, Eel, and Specification · Tom Harding Fantasy
- 1.14.4. https://jrsinclair.com/articles/2020/whats-more-fantastic-than-fantasy-land-static-land/
- 1.14.5. How to deal with dirty side effects in your pure functional JavaScript
- 1.15. Functional Programming in JavaScript, Part 1: The Unit
- 1.16. Eric Normand - Functional Programming and Clojure
- 1.17. “Simple Made Easy” - Rich Hickey (2011) - YouTube process
- 1.18. Transforming Programming • Dave Thomas • YOW! 2018 - YouTube process
- 1.19. TICKLER Haskell in Enterprise: Interview with Rob Harrison track
- 1.20. Declarative vs Imperative
- 1.21. https://github.com/jaalonso/Lecturas_GLC
- 1.22. Currying: Partial Functions in Python Inheritance in Functional Programming
- 1.23. No Ghosts! · sunfishcode’s blog
- 1.24. Functional Programming in JavaScript, Part 1: The Unit
- 1.25. Why Functional Programming Matters • John Hughes • YOW! 2017 - YouTube
- 1.25.1. Functional Geometry
- 1.25.2. Program with whole values, not one word at a time
- 1.25.3. Combining forms
- 1.25.4. Simple laws
- 1.25.5. Function representation
- 1.25.6. Papers
- 1.25.6.1. Why Functional Programming Matters
- 1.25.6.2. Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs
- 1.25.6.3. Haskell vs. Ada vs. C++ vs. Awk vs. … An Experiment in Software Prototyping Productivity
- 1.25.6.4. The Design of a Pretty-printing Library
- 1.25.6.5. QuickCheck - Wikipedia
- 1.25.6.6. muFP, a language for VLSI design | Proceedings of the 1984 ACM Symposium on LISP and functional programming
- 1.25.7. Consumers vs Producers
- 1.26. Charlas
- 1.26.1. Functional Programming for Pragmatists • Richard Feldman • GOTO 2021 - YouTube
- 1.26.1.1. Objetivo de la charla
- 1.26.1.2. Ámbito rendimiento desarrollo y ecosistema son los puntos de los que va a tratar
- 1.26.1.3. Scope (Ámbito de la charla)
- 1.26.1.4. Rendimiento
- 1.26.1.5. https://www.youtube.com/watch?v=3n17wHe5wEw#t=18m58s
- 1.26.1.6. “Outperforming Imperative with Pure Functional Languages” by Richard Feldman - YouTube
- 1.26.1.7. Tests y refactorización
- 1.26.1.8. Variables globales
- 1.26.1.9. https://www.youtube.com/watch?v=3n17wHe5wEw#t=32m25s de qué color es tu función es un artículo que dice que si quieres modificar una lista de funciones enlazadas para llamar a una función que devuelve una tarea tienes que modificar todas para que devuelvan a una tarea
- 1.26.1.10. https://www.youtube.com/watch?v=3n17wHe5wEw#t=35m00s si tú llamas a una función de un paquete pero ese paquete se actualiza y me pasa a tener efectos secundarios te puede romper tu función pura porque si llama una función con efectos secundarios dejar de ser pura
- 1.26.1.11. Si el ecosistema no está muy centrado en hacer las funciones puras entonces pierdes esto
- 1.26.1.12. https://www.youtube.com/watch?v=3n17wHe5wEw#t=36m00s de la charla de programación funcional él es un lenguaje de programación funcional basado que luego compila a javascript con su propio sistema de paquetes que te segura que son funcionales
- 1.26.1.13. Al final el valor de un lenguaje de programación también están sus ecosistemas porque si está programado pensando de manera funcional te aseguras que las funciones son puras
- 1.26.1. Functional Programming for Pragmatists • Richard Feldman • GOTO 2021 - YouTube
- 1.27. Erlang
- 1.27.1. Erlang, the Hidden Gem: Solving Problems at Scale for 30+ Years • Francesco Cesarini • GOTO 2021 - YouTube
- 1.27.1.1. https://www.youtube.com/watch?v=-m31ag9z4VY#t=5m00s: erlang tiene tres cosas
- 1.27.1.2. Elixir es un lenguaje que compila a erlang
- 1.27.1.3. Modelo de tareas de erlang
- 1.27.1.4. Akka (réplica en Java de la máquina virtual de erlang)
- 1.27.1.5. https://www.youtube.com/watch?v=-m31ag9z4VY#t=20m00s utilizar elixir y erlang para edge computing
- 1.27.1.6. https://www.youtube.com/watch?v=-m31ag9z4VY#t=21m00s el git de elixir numerical framework y action son librerías que han contribuido para hacer esto posible
- 1.27.2. Erlang’s not about lightweight processes and message passing : programming
- 1.27.3. https://learnyousomeerlang.com/
- 1.27.4. Towards zero-downtime upgrades of stateful systems
- 1.27.1. Erlang, the Hidden Gem: Solving Problems at Scale for 30+ Years • Francesco Cesarini • GOTO 2021 - YouTube
- 1.28. Reactive programming - Wikipedia
- 1.29. The topos theory of computing: introduction to the mathematics of dataflow
- 1.30. https://en.wikipedia.org/wiki/Structured_program_theorem
- 1.31. Producer-consumer problem
- 1.32. Semantics (computer science) - Wikipedia
- 1.33. Algebraic semantics (computer science) - Wikipedia
- 1.34. Robert Harper’s Home Page
- 1.35. Functional programming ideas idea
- 1.35.1. Testing as map of
test_data
and partial equality (Observational Equivalence) - 1.35.2. MapReduce is just a lisp progn (DAG) / (Almost) everything is a progn / Everything is a Stream
- 1.35.3. Pattern Matching as inverse construction (deconstruction)
- 1.35.4. Seamless Scaling
- 1.35.5. Functional Programming in Bash(?)
- 1.35.1. Testing as map of
- 1.36. Igualdades
- 1.37. Types
- 1.38. Parser Combinators
- 1.39. Languages
- 1.40. Data Flow Analysis
- 1.41. Haskell GUI Libraries
- 1.42. GitHub - nobuyuki83/floor_plan
1. functional programming
1.1. Monads
1.1.1. notebook.community Monads
A monad is just a monoid in the category of endofunctors, what’s the problem? -Philip Wadler
1.1.2. Monads and Python – Code happens
In Haskell, the compiler is free to run those functions in either order as there is no data dependency between them. In Python, it is not – the order is specified directly by the code. Haskell requires a data dependency to force ordering (and in fact RealWorld in order to distinguish different invocations of IO)
«Just like the ordering problem with the jupyter notebooks»
https://www.reddit.com/r/Python/comments/qvte5l/monads_and_python/
1.1.4. http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html?m=1
Clear and understandable
1.2. Conceptos
1.2.1. https://en.wikipedia.org/wiki/Memoization
In computing, memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.
The key is that pure functions can be substituted unambiguously by a lookup table (given X, Y arguments, the output is always Z)
1.2.2. Funciones honestas/transparentes en vez de funciones puras
También se conocen como transparentes: https://en.wikipedia.org/wiki/Referential_transparency
If all functions involved in the expression are pure functions, then the expression is referentially transparent.
An expression is called referentially transparent if it can be replaced with its corresponding value (and vice-versa) without changing the program’s behavior.
Parece que es un mejor término utilizar funciones honestas/transparentes en vez de funciones puras
- No tiene más entradas ocultas (es decir, más argumentos de los que toma)
- No tiene más salidas de los que devuelve (es decir, efectos secundarios)
1.2.3. Combinators
Combinator - HaskellWiki
A function or definition with no free variables.
https://en.wikipedia.org/wiki/Combinatory_logic
A combinator is a higher-order function that uses only function application and earlier defined combinators to define a result from its arguments.
loophp/combinator: A curated list of combinators
1.2.4. Idempotent
An operation/function that applied multiple times leaves the system as if was applied only once
Applying it 2 times is the same than applying it once
1.2.4.1. Idempotency key/token
A token that is sent with a function to be executed, to ensure it’s only executed once even if the request is sent multiple times (for example, avoid duplicate orders, or delete the oldest log file even if two requests come along)
1.2.5. Models of computation
- https://en.wikipedia.org/wiki/Model_of_computation
- How to declare an imperative | ACM Computing Surveys
Descartes pondered the mind body problem: how can incorporeal minds interact with physical bodies?
Today (1997) computing scientists face their own version of the mind body problem: how can virtual software interact with the real world?
Interaction is the mind body problem of computing
1.2.6. Types of evaluation
1.2.6.1. Evaluation strategy - Wikipedia
1.2.6.2. Lazy evaluation - Wikipedia
1.2.6.3. Partial evaluation - Wikipedia
1.2.6.4. Remote evaluation - Wikipedia
1.2.6.5. Short-circuit evaluation - Wikipedia
- Parallel short-circuit evaluation
If you have a bunch of subpredicates joined by and/or, then you can apply short-circuit evaluation in parallel, when one of the probes fails/succeeds, then you don’t have to wait for the other probes to finish and evaluate the predicate as false/true
1.2.7. Universal Search Algorithm
The method consists in interleaving the execution of all possible programs on a universal Turing machine, sharing computation time equally among them, until one of the executed programs manages to solve the given inversion problem.
If there exists a program \[p\], of length \[l(p)\], that can solve the problem in time \[time(p)\], then Universal Search will solve the problem in a time \[2^{l(p)+1}time(p)\] at most. This exponential growth of computational cost in the algorithmic complexity \[l(p)\] of the fastest solver makes practical applications of Universal Search problematic: nonetheless, the algorithm has inspired various others, including Hutter Search, the Optimal Ordered Problem Solver (OOPS) and the Gödel Machine.
1.2.9. Constraint programming
1.3. Lisp Goodness
1.3.1. https://sites.google.com/site/steveyegge2/tour-de-babel
Two different paradigms
- C -> von Neummann machine
- Lisp -> Lisp machine
1.3.3. http://www.paulgraham.com/onlisp.html
We can approach programming in a different way, if we have the right tools.
Why do we plan before implementing? The big danger in plunging right into
a project is the possibility that we will paint ourselves into a corner. If we had
a more flexible language, could this worry be lessened? We do, and it is. The
flexibility of Lisp has spawned a whole new style of programming. In Lisp, you
can do much of your planning as you write the program.
1.3.6. Greenspun’s tenth rule - Wikipedia
Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.
1.3.8. Little LISPer, The Seasoned Schemer & The Little Schemer
1.5. Pros and cons of fluent interfaces / method chaining / Pointfree style / Tacit programming
- FluentInterface
- Fluent interface - Wikipedia
- Errors cannot be captured at compile time
In typed languages, using a constructor requiring all parameters will fail at compilation time while the fluent approach will only be able to generate runtime errors, missing all the type-safety checks of modern compilers. It also contradicts the “fail-fast” approach for error protection. - Debugging and error reporting
Unclear which function call has caused the error, and debuggers are line-oriented, (“step” while debugging is not function oriented for example)
These issues can be overcome by breaking the statement into multiple lines which preserves readability while allowing the user to set line breakpoints
PEP 657 : Fine grained locations in tracebacks merged to Python 3.11 - Logging
Adding logging into the middle of a chain of fluent calls can be an issue.
This can be worked around in languages that support extension methods by defining a new extension to wrap the desired logging functionality - Subclasses
Subclasses in strongly typed languages (C++, Java, C#, etc.) often have to override all methods from their superclass that participate in a fluent interface in order to change their return type.
Languages that are capable of expressing F-bound polymorphism can use it to avoid this difficulty. For example:
In a dependently typed language, e.g. Scala, methods can also be explicitly defined as always returning this and thus can be defined only once for subclasses to take advantage of the fluent interface:
- Errors cannot be captured at compile time
- Method chaining - Wikipedia
- Tacit programming - Wikipedia
- Fluent Interfaces are Evil
- Command–query separation - Wikipedia
It states that every method should either be a command that performs an action, or a query that returns data to the caller, but not both. In other words, asking a question should not change the answer. More formally, methods should return a value only if they are referentially transparent and hence possess no side effects.
1.6. Rewriting / Refactorization
1.7. Avoid shared mutable state
Mutable state is fine, as long as it’s now shared
Shared state is fine, as long as it’s now mutable
This can be converted into a continuum?
Mutable state → change of rate of that state, or variable: information
Shared state → scope of that variable, dependencies
Something like “The Stable Abstractions Principle” in Clean Architecture (pg127)
1.9. Climbing Mount Effect
Cómo programar declarativamente con lenguajes imperativos
Cómo programar funcionalmente con lenguajes imperativos
Some combination of events or interactions corrupts the game’s state in some way. Something changed when it shouldn’t have, or the other way around.
1.9.1. Delta code
The problem is that this code is written as delta-code. It describes state changes, rather than the states themselves. Because there are O(N²) arrows, there will potentially be O(N²) lines of code for dealing with N states.
The real reason to write declarative code is to produce code that is O(N) lines instead. This work does not get harder over time. This is generally not taught in school because neither the students nor their teachers have spent enough time in one continuous codebase.
The goal is to have most code only declare intent. Then you use other code to reach that target, no matter what the prior state was.
1.9.2. Strange Effects
constructor() { // Enter state - on } onUpdate() { // Exit old state - off // Enter new state - on } dispose() { // Exit state - off }
The trick to fix it is mainly just slicing the code differently, e.g. using a generator:
let effect1 = function* () { // Enter state - on yield // Wait // Exit state - off } let effect2 = function* () { // Enter state - on yield // Wait // Exit state - off }
From | To |
---|---|
constructor() | Call effect |
onUpdate() | Cleanup effect |
Call effect | |
onUpdate() | Cleanup effect |
Call effect | |
onUpdate() | Cleanup effect |
Call effect | |
dispose() | Cleanup effect |
It doesn’t have fewer calls, just fewer unique parts.
1.9.2.1. effects as a formal type
They are similar to async=/=await
and promises. But effects and promises are subtly different. A promise represents ongoing work. An effect is merely a description of work «that you submit to an executor». The difference is:
- In a promise-based API,
fetch(url) => Promise
will run a new HTTP request - In an effect-based API,
fetch(url) => Effect
will describe an HTTP request
As a first approximation, you can think of an effect-based API as:
fetch(url) => () => Promise
It won’t actually start until you call it a second time
If a fetch
promise fails, there is no way for you to retry using the promise itself. Each is one-use-only. You have to call fetch(url)
again to get a fresh one. You need to know the specific type of promise and its arguments.
But if a fetch
effect fails, then you can retry the same effect just by passing it back to your effect run-time. You don’t need to know what effect it is.
1.9.2.2. retry combinator
If an error happens, it returns another copy of itself, but with the retry count reduced by 1, until it reaches 0:
let attemptRetry = (effect, n) => function* (i, e) { // Make request const [value, error] = yield [effect, i, e]; // Success if (value) return [null, value]; // Retry n times if (n > 0) return attemptRetry(effect, n - 1); // Abort return [null, null, error]; }
1.9.2.3. It’s about the process of making things happen, not the actions themselves.
You can focus purely on defining and declaring intended effects, while letting a run-time figure out how to schedule and execute them. In essence, an Effect
is a formalization of 🤙 aka (...) =>
. It’s about the process of making things happen, not the actions themselves.
Whether effects are run serially or parallel depends on the use case, just like promises. Whether an effect should actually be disposed of or undone is also contextual: if it represents an active resource, then disposal is necessary to ensure a clean shutdown. But if an effect is part of a transaction, then you should only be rolling it back if the effect chain failed.
But know that even just () => Promise
, () => Generator
and () => void
can solve a whole bunch of issues elegantly.
1.9.3. Disposable
1.10. What’s Functional Programming All About?
- What’s functional programming all about? (2017) | Hacker News
Consider async-await a syntactic sugar over Promises (from JavaScript). Then, Promises constitute an instance of the Monad typeclass where monadic `bind` or (>>=) is `Promise.then()`, and `return` is `Promise::resolve()`.
1.12. Effects and CoEffects
1.13. SMC: The State Machine Compiler
Enter SMC - The State Machine Compiler. Now you put your state diagram in one file using an easy-to-understand language. SMC generates the state pattern classes for you. No more hand-maintained transition matrices. No more widely scattered switch statements. Instead, the state diagram is in one place, coded directly from the picture to the SMC language and is easily maintained.
1.14. jrsinclair process
1.14.1. What if the team hates my functional code?
- implicit
notifications
const renderNotifications = flow( map(addReadableDate), map(addIcon), map(formatNotification), map(listify), wrapWithUl );
- explicit
notifications
, unusual syntax
const renderNotifications = (notifications) => pipe( notifications, map(addReadableDate), map(addIcon), map(formatNotification), map(listify), wrapWithUl );
- chained methods and functions
const renderNotifications = (notifications) => wrapWithUl( notifications .map(addReadableDate) .map(addIcon) .map(formatNotification) .map(listify) );
- introduce one variable to avoid chaining functions and methods
const renderNotifications = (notifications) => { const renderedItems = notifications .map(addReadableDate) .map(addIcon) .map(formatNotification) .map(listify); return wrapWithUl(renderedItems); };
- separate in multiple assignments, still functional code
const renderNotifications = (notifications) => { const withDates = notifications.map(addReadableDate); const withIcons = withDates.map(addIcon); const formattedItems = withIcons.map(formatNotification); const listItems = formatedItems.map(listify); return wrapWithUl(listItems); };
1.14.3. Things I wish someone had explained about functional programming
1.14.3.1. Algebraic Structures: Things I wish someone had explained about functional programming
Words like ‘monoid,’ ‘applicative,’ ’semiring,’ ‘lattice,’ ‘functor,’ or the dreaded ‘monad’? The collective term for these concepts is algebraic structures.
Maybe, Either, and Effect (also known as ‘IO’). We use Maybe, Either, and Effect for different purposes:
- Maybe helps us deal with
null
orundefined
values; - We can use Either to handle errors; and
- Effect gives us control over side effects.
- Maybe, Either, and Effect all have a
.map()
method. Each one also has.ap()
and.of()
methods. And all three have.chain()
too. - Algebraic structures are “metaclasses”
Why do we use classes for anything? Because they abstract common behaviour. That behaviour is shared between a bunch of objects. Algebraic structures, in turn, abstract common patterns shared between a bunch of classes.
1.14.3.2. Type Classes: Things I wish someone had explained about functional programming
Type classes are used to implement algebraic structures. They’re a language feature, rather than a mathematical concept.
Type classes are a way of doing polymorphism
1.14.3.3. Algebraic Data Types: Things I wish someone had explained about functional programming
An algebraic data type is a structured type that’s formed by composing other types. Or, even shorter, it’s a type made of other types.
Product types, sum types
Maybe, Either, and Effect, Reader, Future (also known as Task), and State
1.14.3.5. Fantas, Eel, and Specification · Tom Harding Fantasy
1.14.4. https://jrsinclair.com/articles/2020/whats-more-fantastic-than-fantasy-land-static-land/
So, a simple Maybe implementation might look like this: (Type hints)
1.14.5. How to deal with dirty side effects in your pure functional JavaScript
There’s two main ways they do this:
- Dependency injection, or as I call it, chucking the problem over the fence; and
we take any impurities in our code, and shove them into function parameters. Then we can treat them as some other function’s responsibility.
- ↓ lengthy function signatures
- ↓ lengthy function signatures
- Using an Effect functor, which I think of as extreme procrastination.
1.17. “Simple Made Easy” - Rich Hickey (2011) - YouTube process
1.18. Transforming Programming • Dave Thomas • YOW! 2018 - YouTube process
From the Pragmatic Programmer, very focused on actual programming and good habits
1.19. TICKLER Haskell in Enterprise: Interview with Rob Harrison track
My working title is ‘Theory in the Category of Code’. Basically, I find myself on a daily basis having the same discussions over and over about what I consider in our industry to be essentially solved problems or answered questions in industry best practices. My book started out as a way I could share a chapter with my team to avoid having to have the same conversations over and over. For example, I can’t believe we’re still having to have conversations about the efficacy and efficiency of TDD. For me, on anything but the smallest projects, TDD is a must to avoid the project grinding to a halt as it grows.
1.20. Declarative vs Imperative
1.22. Currying: Partial Functions in Python Inheritance in Functional Programming
Generally, partial application is analogous to inheritance from a general class to a more specialized class.
1.23. No Ghosts! · sunfishcode’s blog
Web Assembly
The ideas in this post aren’t new; they come from papers and blog posts such as Robust Composition, Capabilities: Effects for Free, Parse, don’t validate, the nanoprocess model, and the design choices in the Wasm component model, which itself incorporates ideas from Erlang, OCaml, Rust, COM, and many others.
1.23.1. Ghosts?
By “ghost” here, I mean any situation where resources are referenced by plain data.
And by “plain data” here, I mean strings, integers, or any other data where independently produced copies of the data are interchangeable
For example a path string: while paths are explicit string parameters, the additional information referenced by those paths is not.
IP addresses are another example of plain data that references other resources
Ghosts can also occur within key-value stores, registries, brokers, buses, and many other things where the identifiers are plain data.
1.23.2. The trouble with ghosts
Ghosts are often convenient, in the way that duct tape is convenient. They can quickly connect two things, even in a large system, without extensive changes.
- Ghosts have four distinct problems as systems scale up in complexity:
- Ghosts don’t always go to the places we want them to 👻➡😞. Unresolved or bad resolved references
- Ghosts may go places we don’t want them to 👻➡😲. A process inherits environment variables, a subclass inherits attributes/methods, aliasing of variables prevents full deletion
- Ghosts may collide with other ghosts 👻➡💥⬅👻. Namespace collision, env variable overriding
- And sometimes, ghosts come from places they’re not expected to ❓➡👻. Security vulnerabilities, data as code
- Ghosts don’t always go to the places we want them to 👻➡😞. Unresolved or bad resolved references
- Ghosts complicate static analysis
- Ghosts complicate debugging
You can’t isolate components: components work differently when run independently than when they’re run together, or work differently in different environments, - Ghosts are often a sign of over-sharing
Over-sharing happens when a component is given access to resources that it doesn’t need.
This often happens in namespace-oriented systems because it’s difficult to precisely configure namespaces to be fine-grained - Ghosts can contribute to confused deputies
(Cross-site request forgery is an example)
1.23.3. How to smell a ghost
- String parameters which don’t represent user data.
A string that is really a text field, filename, database_id
Heuristic: “Strings are for humans” 🌟 - The word “the”.
Whenever we find ourselves thinking about the filesystem, the network, the process, the host, the OS, or the computer, it often means we’re making assumptions about state that might be shared
Heuristic: “Components should be hostless” 🌟 - User identity outside the user interface.
Heuristic: “Handles are permissions” 🌟
1.24. Functional Programming in JavaScript, Part 1: The Unit
Explicado de manera simple
https://marmelab.com/blog/2018/03/14/functional-programming-1-unit-of-code.html
1.25. Why Functional Programming Matters • John Hughes • YOW! 2017 - YouTube
1.25.1. Functional Geometry
1.25.2. Program with whole values, not one word at a time
For example defining operations in vector and matrices and not iterating through the elements of a vector to do an scalar product
1.25.3. Combining forms
1.25.4. Simple laws
Transformations on the code that leave its behavior unchanged
Algebra as a litmus test for good design (finding definitions that satisfy simple laws is indicative of good design)
1.25.5. Function representation
Every value can be represented as a function
Is this getter/setters?
1.25.6. Papers
1.25.6.1. Why Functional Programming Matters
1.25.6.2. Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs
Recommends reading the first part, until IO stuff
The von Neumann computer,
- their close coupling of semantics to state transitions,
- their division of programming into a world of expressions and a world of statements (in individual items instead of in whole conceptual units)
- their inability to effectively use powerful combining forms for building new programs from existing ones (lack good abilities for combination, are too rigid for that), and
- their lack of useful mathematical properties for reasoning about programs.
1.25.6.4. The Design of a Pretty-printing Library
1.25.6.5. QuickCheck - Wikipedia
- QuickCheck: An Automatic Testing Tool for Haskell
QuickCheck is a tool for testing Haskell programs automatically. The programmer provides a specification of the program, in the form of properties which functions should satisfy, and QuickCheck then tests that the properties hold in a large number of randomly generated cases. Specifications are expressed in Haskell, using combinators defined in the QuickCheck library. QuickCheck provides combinators to define properties, observe the distribution of test data, and define test data generators.
- QuickCheck: Automatic testing of Haskell programs
1.25.7. Consumers vs Producers
The Consumer demands values and it drives the producer to produce them
- Example 1
- Consumer
- function that uses a finite part of that infinite list (both for iteration or recursion for example)
- Producer
- infinite list
- Example 2
- Consumer
- Convergence test
- Producer
- Numerical approximations
- Example 3
- Consumer
- Search strategy
- Producer
- Search space
- Example 4 → The Design of a Pretty-printing Library
- Consumer
- Selection for the best layout
- Producer
- Ways to layout a document
- Example 5 → QuickCheck - Wikipedia
- Consumer
- QuickCheck search strategy
- Producer
- Space of all possible tests
- Random search to encounter a failing case, and then systematic search to find the simplest failing case
- Random search to encounter a failing case, and then systematic search to find the simplest failing case
- Example 6
- Consumer
- Selection criterion for lowest power
- Producer
- Ways to lay out a parallel prefix circuit
1.26. Charlas
1.26.1. Functional Programming for Pragmatists • Richard Feldman • GOTO 2021 - YouTube
1.26.1.1. Objetivo de la charla
Objetivo → ver las razones concretas y objetivas por las que utiliza la programación funcional en vez de imperativa
Por que normalmente las razones que da la gente suelen ser subjetivas
1.26.1.2. Ámbito rendimiento desarrollo y ecosistema son los puntos de los que va a tratar
1.26.1.3. Scope (Ámbito de la charla)
- Definición de programación funcional
- evitar mutar
- evitar los efectos secundarios
- evitar mutar
- Lenguaje de programación funcional puro
los lenguajes de programación puros son solo los que permiten funciones puras
- Alcance de la charla
Inmutabilidad, funciones puras, y lenguajes funcionales
No se consideran Pattern matching, polimorfismo y type checking
- Definición de funciones puras
- Toman siempre los mismos argumentos
- Devuelven siempre el mismo valor
- No tienen efectos secundarios
- Toman siempre los mismos argumentos
- Las funciones puras se pueden sustituir por una tabla
Lookup table
1.26.1.4. Rendimiento
- Cacheo y memoización
- Precomputación
si estás llamando a una función pura con argumentos que son constantes en tiempo de compilación el compilador puede sustituir esa función por una constante
- Concurrencia
Si estás utilizando la función map y estás llamando a funciones puras entonces puede sustituir esa llamada por un map paralelo, y además es seguro ante problemas de concurrencia
- Los problemas de concurrencia (data races) tampoco ocurren si no mutas los datos y no hay mutaciones concurrentes
- Esta no es la única manera de hacerlo y en Rust puedes declarar estas mutaciones de datos y te lo gestiona internamente
- Los problemas de concurrencia (data races) tampoco ocurren si no mutas los datos y no hay mutaciones concurrentes
- Problemas de rendimiento
las mutaciones en el momento pueden ser más rápidas en lenguajes imperativos
los efectos gestionados (managed effects) pueden tener también un poco más de coste computacional
- Promises vs Tasks
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=27m38s las promesas en javascript se ejecutan justo después de que las definas entonces eso esté genera efectos secundarios al momento en cambio los defectos gestionados de volverse una tarea pero realmente lo que creas es una cadena de tareas que dependen unas de otras y al final llamas esa
- Pérdida de rendimiento como tienes que declarar toda la estructura de tu programa tienes que guardar eso de alguna manera en el código si no utilizas promesas en javascript por ejemplo lo puedes declarar de manera imperativa y eso va a ser siempre más rápido que tener que declarar cualquier
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=27m38s las promesas en javascript se ejecutan justo después de que las definas entonces eso esté genera efectos secundarios al momento en cambio los defectos gestionados de volverse una tarea pero realmente lo que creas es una cadena de tareas que dependen unas de otras y al final llamas esa
1.26.1.6.
1.26.1.7. Tests y refactorización
- Si tus tests cambian de una vez a otra la ejecución la programación funcional te ayuda con eso porque está evitando los efecto
- Si no tienes efectos secundarios no te hace falta tener mocking
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=22m23s
- Las tareas gestionadas se pueden probar con simulación qué es el equivalente de mocking
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=24m31s si tus funciones son puras entonces las puedes reordenar y llamarlas en el orden que quieras
esto también lo implementan las anotaciones de mutaciones como las que tiene rust por ejemplo: más que implementarlo lo alivia porque te dan un warning - Incluso si no tiene efectos secundarios cualquier entrada-salida que haga el programa como por ejemplo escribir una base de datos puede tener estos efectos secundarios y no los cogerías con anotaciones
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=25m36s esto implica al final refactorización más rápida
1.26.1.8. Variables globales
- lo malo de las variables globales que se pueden cambiar mutables es que crean dependencia implícitas
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=27m44s cualquier variable global mutable que añades a tu código añade automáticamente un argumento de salida y uno de entrada a cada función que tengas
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=28m47s los efectos secundarios introducen también dependencias implícitas
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=31m00s el hecho de programar con funciones puras así que cuando estés depurando un error tu espacio de búsqueda sea muchísimo menor
- https://www.youtube.com/watch?v=3n17wHe5wEw#t=31m50s las dependencias visitas son más ver cosas porque si quieres mutar un objeto en programación funcional pura tienes que crear una función que devuelve ese objeto mutado
1.26.1.9. https://www.youtube.com/watch?v=3n17wHe5wEw#t=32m25s de qué color es tu función es un artículo que dice que si quieres modificar una lista de funciones enlazadas para llamar a una función que devuelve una tarea tienes que modificar todas para que devuelvan a una tarea
1.26.1.10. https://www.youtube.com/watch?v=3n17wHe5wEw#t=35m00s si tú llamas a una función de un paquete pero ese paquete se actualiza y me pasa a tener efectos secundarios te puede romper tu función pura porque si llama una función con efectos secundarios dejar de ser pura
1.26.1.11. Si el ecosistema no está muy centrado en hacer las funciones puras entonces pierdes esto
1.26.1.12. https://www.youtube.com/watch?v=3n17wHe5wEw#t=36m00s de la charla de programación funcional él es un lenguaje de programación funcional basado que luego compila a javascript con su propio sistema de paquetes que te segura que son funcionales
1.26.1.13. Al final el valor de un lenguaje de programación también están sus ecosistemas porque si está programado pensando de manera funcional te aseguras que las funciones son puras
1.27. Erlang
1.27.1. Erlang, the Hidden Gem: Solving Problems at Scale for 30+ Years • Francesco Cesarini • GOTO 2021 - YouTube
1.27.1.1. https://www.youtube.com/watch?v=-m31ag9z4VY#t=5m00s: erlang tiene tres cosas
- la primera es el BEAM es la máquina virtual que está optimizada para ejecutarse en múltiples procesadores luego también está
- odp qué es el gestionador de todas las abstracciones de concurrencia para que sea más productivo programar y no pases tiempo con los detalles de bajo nivel
- El tercer punto es que la semántica de erlang se parece mucho al funcionamiento interno de BEAM por lo cual está muy acoplados y funciona muy bien
1.27.1.2. Elixir es un lenguaje que compila a erlang
- Fue creado según su desarrollador para abrir erlang a los desarrolladores web a más programadores en general
- Está más basado para telecomunicaciones erlang
- https://www.youtube.com/watch?v=-m31ag9z4VY#t=9m45s intentaron desarrollar muchos frameworks para web pero ninguno de ellos les dio el resultado que esperaba → crearon elm
1.27.1.3. Modelo de tareas de erlang
- https://www.youtube.com/watch?v=-m31ag9z4VY#t=11m00s utiliza un modelo en el cual los procesos son independientes no comparten estados y si falla uno no falla el resto
- https://www.youtube.com/watch?v=-m31ag9z4VY#t=11m13s árboles de supervisión para organizar los procesos
- https://www.youtube.com/watch?v=-m31ag9z4VY#t=11m46s hay procesos supervisores que lo único que hacen es supervisor si se ejecutan en un proceso y cuando falla toman una acción
- https://www.youtube.com/watch?v=-m31ag9z4VY#t=12m38s este esquema generaliza el gestionado de errores
- El proceso supervisor lidia con las excepciones en vez del propio código: agrupa todo este código que maneja excepciones con lo que reduces duplicación de código https://www.youtube.com/watch?v=-m31ag9z4VY#t=13m56s
1.27.1.4. Akka (réplica en Java de la máquina virtual de erlang)
- https://www.youtube.com/watch?v=-m31ag9z4VY#t=16m00s
- https://www.youtube.com/watch?v=-m31ag9z4VY#t=17m00s akka da más libertad al programador que erlang, por ejemplo en akka los procesos se te pueden morir de hambre (starvation) pero no en erlang (restringe más)
1.27.1.5. https://www.youtube.com/watch?v=-m31ag9z4VY#t=20m00s utilizar elixir y erlang para edge computing
1.27.1.6. https://www.youtube.com/watch?v=-m31ag9z4VY#t=21m00s el git de elixir numerical framework y action son librerías que han contribuido para hacer esto posible
1.27.2. Erlang’s not about lightweight processes and message passing : programming
1.27.2.1. armstrong-distributed-systems/erlang-is-not-about.md at main · stevana/armstrong-distributed-systems
1.27.2.2. Gleam
1.27.3. https://learnyousomeerlang.com/
1.28. Reactive programming - Wikipedia
Variables and functions as producers & consumers
- Variables are not mutable, read-only, but can be shared, like producers (shared data)
- Functions are shared behavior, like consumers
1.28.2. Dependence analysis - Wikipedia
1.28.3. A few programming language features I’d like to see – Neil Madden
Teleo-Reactive programs | Nils Nilsson
approach to programming robots and other systems that is goal-driven but also reacts to unexpected changes in the environment. It doesn’t just keep blindly following a fixed procedure.
The basic idea is that you define a method to achieve some goal as an ordered list of conditions and corresponding actions
If some earlier task was completed but is somehow undone by another action the TRP will notice this the next time it scans through the list and will to that task. On the other hand, if a change in the environment serendipitously causes a higher-up goal to be satisfied already, the system will also notice that and automatically avoid duplicate work.
1.30. https://en.wikipedia.org/wiki/Structured_program_theorem
The structured program theorem, also called the Böhm–Jacopini theorem, is a result in programming language theory. It states that a class of control-flow graphs (historically called flowcharts in this context) can compute any computable function if it combines subprograms in only three specific ways (control structures). These are
- Executing one subprogram, and then another subprogram (sequence)
- Executing one of two subprograms according to the value of a boolean expression (selection)
- Repeatedly executing a subprogram as long as a boolean expression is true (iteration)
1.31. Producer-consumer problem
1.31.1. Rust Is a Scalable Language
Cargo defines a rigid interface for a reusable piece of Rust code. Both producers and consumers must abide by these rules, there is no way around them. As a reward, they get a super-power of working together by working apart.
1.35. Functional programming ideas idea
1.35.1. Testing as map of test_data
and partial equality (Observational Equivalence)
- Observational Equivalence | PLS Lab
Two programs in the same programming language are called observationally equivalent whenever they are interchangeable in all observable contexts.
A test is performing a partial equality, func1 is equal to func2 at least when evaluated using the test-data, to the precision required (it doesn’t have to be strict equality when dealing with floating point numbers)
(eq (map func1 test_data) (map func2 test-data)) (map (lambda (x) (eq (func1 x) (func2 x))) test-data)
Test should be parallelizable and independent of ordering if func1 and func2 are both pure functions
func1 is the function you want to test
func2 is a dictionary of concrete cases
A set with a equivalente relation is called a Setoid, and there is a Setoid Type Theory (SeTT)
- Some more related links when I didn’t know the name of this thing:
1.35.1.1. Test space is not homogeneous
Test space is not homogeneous (I cannot remember where I saw that), errors tend to accumulate near edge cases/corner cases
How to reduce test space?
- Reduce test space: Is there a test with types?
Test ensure partial equality between functions, can types reduce the search space?
With Replicated Data Types as composable types maybe there is a “type of types” and you can optimize the number of tests
Joe Armstrong says on Haskell you can search on types signatures and also on value properties
- Reduce test space: Use hashes of lists of test cases
From 5 Hobby Projects - Joe Armstrong - EEF17
Divide your input in lists, hash the input, and hash the output
You can turn any data structure into a integer by using Gödel Numbering/Mapping
1.35.1.2. Metamorphic testing - Wikipedia
1.35.1.3. Test oracle - Wikipedia
1.35.1.4. Testing is undecidable
https://stackoverflow.com/questions/1132051/is-finding-the-equivalence-of-two-functions-undecidable
https://stackoverflow.com/questions/9906628/equality-of-functions-in-haskell
deciding whether two functions are equal for all possible inputs (without just checking every input value, if that is even possible) is equivalent to solving the Halting problem.
1.35.2. MapReduce is just a lisp progn (DAG) / (Almost) everything is a progn / Everything is a Stream
progn here means: recursive list of functions than can be composed in parallel or sequentially (one after another) → tree-like structure?
Map → execute independent stuff
Reduce → execute dependent stuff
MapReduce
This is just a DAG
1.35.2.2. Structure and Interpretation of Computer Programs book
1.35.2.3. Interesting language that seems to have been overlooked: the almost-turing-complete Alan language : programming
- The Turing-Completeness Problem - Alan Language
The following snippet of C code succinctly contains the problems of Turing completeness complicating modern development:
while (node) { doSomethingWith(node); node = node->next; }
- Automatic Parallelization - It’s not possible to automatically parallelize this code. The number of nodes is not clear to the compiler for it to potentially bunch those calls across threads, and it’s also unclear if the function call mutates the node and adds/removes nodes to process.
- Halting Problem - It’s not possible to know if the code will halt, even ignoring the idea that
doSomethingWith
may always add a newnode
to the one it is processing, there’s nothing stopping a node from pointing at itself and never halting that way.
with minor syntax constraints (that we believe the vast majority of developers will not notice, or at least won’t mind) we can be sure that the code you write always halts, and we can parallelize your code for you
- Automatic Parallelization - It’s not possible to automatically parallelize this code. The number of nodes is not clear to the compiler for it to potentially bunch those calls across threads, and it’s also unclear if the function call mutates the node and adds/removes nodes to process.
1.35.3. Pattern Matching as inverse construction (deconstruction)
immutability […] makes construction reversible. Given an object, you can always disassemble it down to parts that were used in its construction. This deconstruction is done with pattern matching and it reuses constructors as patterns. Constructor arguments, if any, are replaced with variables (or other patterns).
1.35.4. Seamless Scaling
Pasar de manera sencilla de unas cosas a otras que no te lleve a hacer grandes refactorizaciones
1.35.4.1. Programación OOP en Go para pasar de imperativo a oop de manera fluida
Lo que vas haciendo es que si declaras una clase de un argumento con su tipo correspondiente, luego se puede llamar con sintaxis de oop y no tienes que hacer refactor para cambiarlo
Una clase es simplemente una agrupación de funciones cuyo primer método tiene el mismo tipo
1.35.4.2. Variables y funciones como productores y consumidores
- Las variables son constantes y sólo lectura, pero son compartidas. Son como los productores(?)
- Las funciones son comportamientos compartidos. Son como los consumidores(?)
1.35.4.3. Hay una manera sencilla de pasar de diccionarios a objetos?
Por ejemplo en javascript por defecto es así
1.35.5. Functional Programming in Bash(?)
1.35.5.1. Functional Programming in Bash. simple ways and means to be more… | by joydeep bhattacharjee | Medium
1.35.5.2. UNIX pipes as IO monads
1.35.5.3. The Point of Pointfree
1.35.5.4. Parallel piping
Bash represents piping well, and you can parallelize over its elements. However how can you express paralelization more naturally?
For example redirect the output of a pipe to two different sources and build a DAG
rg -H "https?://" \ | sed -E 's%(.+\.org)\:.+?(https?://[^] ]+).+?%\1|\2%g' \ | parallel --colsep '\|' curl -o /dev/null -s -w '{1}\|{2}\|%{http_code}\\n' '{2}' \ | tee -a "link_rot $now.csv"
- Not all Graphs are Trees • Buttondown
You can do this with text: o / \ o o \ / o But there is not a way to "pass through": o / \ o---o \ / o You need and "identity" node because each step is ... | a | b | c | ... : you cannot connect a with c without passing through b o / \ o-i-o \ / o
There are similar constraints when using sets and written language:
- [2405.10387] Grothendieck’s use of equality
(a, b) = (c, d) means a = c and b = d because you write a sequence of letters as an ordered sequence. could have (b, a) = (c, d) or any other disordered spatial representation (2D, 3D, …)
1.36. Igualdades
Igualdad entre igualdades: funciona en mi máquina = funciona en tu máquina
1.37. Types
1.37.1. Abstract Data Types
1.37.2. Type of types
1.37.3. Quantitative Type Theory
1.37.4. ATS: Why Linear Types are the Future of Systems Programming
1.37.5. Covariance and contravariance (computer science) - Wikipedia
Robustness principle - Postel’s Law in Software: Argument types are contravariant with respect to subtypes (i.e., you can accept a subtype as an argument, but not a supertype), return types are covariant with respect to subtypes (you can return a subtype, but not a supertype)
Luciano Ramalho recomienda anotar las los argumentos con clases abstractas pero las cosas que devuelves con tipos concretos
1.37.6. Church vs Curry Types
Church types (intrinsic types, Haskell) → sound type system
Curry types (extrinsic types, Clojure/Python,Typescript)
Intrinsic types are great because you are guaranteed to have a mathematically-sound safety net at all times. You always have something you can reason about. Such is not guaranteed for extrinsic type checkers. They may not be able to reason about your code at all.
Extrinsic types are useful because you can apply multiple type systems to your code –or even write something that you don’t know how to prove is sound
1.38. Parser Combinators
- https://deepsource.com/blog/monadic-parser-combinators
- https://www.cs.nott.ac.uk/~pszgmh/monparsing.pdf
a popular approach to building recursive descent parsers is to model parsers as functions, and to define higher-order functions (or combinators) that implement grammar constructions such as sequencing, choice, and repetition (Structured program theorem). Such parsers form an instance of a monad
1.39. Languages
1.40. Data Flow Analysis
Alternativas Sourcetrail
Documents/3resources/Informatica/Data Flow Analysis Theory and Practice.pdf
Documents/3resources/Informatica/Harper, Robert Practical foundations for programming languages Cambridge University Press 2016 1.pdf
1.40.1. To convert a data flow diagram into categorical diagrams, swap nodes and arrows
1.41. Haskell GUI Libraries
1.42. GitHub - nobuyuki83/floor_plan
1.42.2. Differentiable Programming from Scratch
:ID: 07443a88-d799-48ab-a4a4-b4a0f1bc792b