Topics differ a lot, whatever captures my attention ends up here. Notes are written by me (click the ▶ to see them), usually they sum up video contents, have a look to get a eagle eye view, do not expect a complete summary.
These are the channels where I get most of my sources.
- Algorithms and data structures
- Art
- Category Theory
- Combinators
- Cyber security
- DIY
- Fun
- Functional programming
- Gaming
- Health
- Idris
- Math
- miniKanren
- Music
- Politics
- Programming
- Science
- Spacemacs
- Sports
- TDD
- The craft
- Types
- TypeScript
- UX
- Web dev
CSE373 2012 - Introduction to Algorithms
This is a course held by prof Skiena, it's a regular university course so it's pretty long, I've liked it as it gave me some background on the matter, "some" because it's not an area I find particularly interesting, but if you do this might be worth. Oh, and prepare to hear lots of "oooook"s and "any questions"s.
All my notes here were taken on paper, before I created this repo.
Bob Ross - A Walk in the Woods (Season 1 Episode 1) (28:01)
"We start with a vision in our heart and then we put it in our canvas."
While he's drawing trees: "This son of a gun was hiding in the brush the whole time, I just needed to push him out."
"In that time you stayed there worrying about doing or not a painting you could've done one, just let it happen."
Bob Ross - Mt. McKinley (Season 1 Episode 2) (28:32)
I didn't really like the music in background as it distracts from Ross' voice, but the beauty of the painting made me go through nonetheless.
Bob Ross - Campfire (Season 3 Episode 10) (26:32)
Love the sound the knife makes while colors are being mixed and then applied to the canvas.
"Use your imagination. Let your heart take wherever you wanna go."
When talking about how a portrait teacher told him to go back to trees and bushes, because "...that's where your heart is.": "Talent is nothing more than a pursued interest".
"You really want painting to make you happy. That is all it is about."
Particular thing to notice about this painting is that he painted a man, it's something rare in Bob Ross' paintings.
Bob Ross - Purple Splendor (Season 4 Episode 1) (27:41)
"...we just sort of let these paintings flow right out of our heart, and you can too... that's what makes it so fantastic."
"This is your world, you create the illusions that you want."
Bob Ross - Northern Lights (Season 8 Episode 13) (27:20)
"God was really having a good day when he made Alaska."
Bob Ross - An Arctic Winter Day (Season 26 Episode 6) (24:50)
I followed along this episode and painted my own version.
Bob Ross - Island in the Wilderness (Season 29 Episode 1) (25:09)
Happy and calm.
"Everyone needs a friend".
"We don't make mistakes, just happy accidents".
Bob Ross - Mountain Lake Falls (Season 29 Episode 6) (25:22)
"When painting a cloud you have to think like a cloud..."
Bob Ross - Reflections of Calm (Season 31 Episode 1) (25:49)
I followed along this episode and painted my own version.
Bob Ross - Winding Stream (Season 31 Episode 3) (25:04)
I followed along this episode and painted my own version.
Category Theory 1.1: Motivation and Philosophy (46:45)
If you want to deal with more complex problems you have to be able to chop the bigger problems into small problems, solve them separately and then combine the solution together: composability. And that's what this is all about.
Abstraction plus composability gives reusability.
Problems with OO are mutations and shared data, which mixed up has a name: data races.
Ideas could be expressed in this higher level language (category theory), and later translated into a lower level language.
Category theory is about reasoning about problems.
Category Theory 1.2: What is a category? (48:17)
Major tools in our arsenal:
- abstraction
Get rid of the unnecessary details, "forget about assembly language". Things that were different because of unnecessary details become identical, two biliard balls might be different under the microscope, but you can replace one for another when you play.
- composition
If you have an arrow from a
to b
(f
) and from b
to c
(g
), then there always must
exist an arrow that goes from a to c (g ∘ f
, which is read as "g after f").
Going from a
to b
using f
and going from b
to c
using g
is identical to going fom
a
to c
using g ∘ f
.
Composable means that the end of an arrow is the same as the start of another arrow. The composition of arrows contains information about a Category.
h ∘ (g ∘ f) = (h ∘ g) ∘ f
which is associativity
- identity
For every object there is always an arrow called identity that goes from the object to itself.
So an arrow f
that goes from a
to b
composed with an arrow idb
that goes from b
to b
I will get back an f
.
Or in notation idb ∘ f = f
Composition and identity define Category Theory.
A Category consists of objects and arrows (morphisms). You could picture that as a graph.
A morphism is something that goes from an object to another one. You have objects so that you could mark the start and end of an arrow. You could have 0 or more arrows between two objects, in both directions and from an object to itself.
Types are your objects, functions are your morphisms.
Just by looking at the multiplication table of a set, at the morphisms, you can learn a lot with this data hiding technique that Category Theory offers. A set's interface is its collection of morphisms.
Category Theory 2.1: Functions, epimorphisms (46:13)
Composability and identity are the most important features of a category.
The most important example of a category that we use in programming, is the category of types and functions. The model for types and functions is sets and functions between sets.
A mathematical function between sets is total (defined for all arguments) and pure.
Functions have a direction. Multiple elements from the domain could become a single element in the codomain, also called image.
The inverse cannot happen.
Given a function f :: a -> b
is invertible if there is a function g :: b -> a
, so that
g ∘ f = id
(and also f ∘ g = id
), where id
(identity) is the original element. An
invertible function is called isomorphism.
A function as something directional, a process that takes place in time, a function that
is not invertible is something that increases entropy: you can't unboil an egg. Abstraction:
I don't care from which point I came from, I am interested about the point in which I end up.
For example the isEven
function, I might get a true
, but I don't know if I started from
2
or 4
.
An injective function does not collapse values into a value. If the image covers all the codomain is called surjective. Injective and surjective makes an isomorphism.
In Category Theory people use Greek, not Latin, so:
- injective -> monomorphism
- surjective -> epimorphism
Category Theory in Life - Eugenia Cheng (40:38)
Sameness, One of the aims of Category Theory
Category Theory is the logical study of the logical study if how logical things work. Things only behave logically in the abstract work of ideas. Take for example London's tube map, it's not realistic, it just represents how stop are connected to each other.
We should study things according to their relations with each other, rather then their intrinsic characteristics. So we should understand everything in context, rather than in isolation. Relations are called morphisms.
Math is all about trying to organise things efficiently, so we can reason about it more efficiently.
Associativity could be explained as "The grandmother of my mother is the mother of my grandmother". Another example is:
- if I mix egg yolk and sugar, then I add milk, and I heat it up, I get custard
- if I mix sugar and milk, and then I mix egg yold, and heat it up, I do not get custard
If I mix sugar, butter, eggs, flour, I can make a cake. The same goes if I mix them in any other order.
Commutativity is the one that enables us to pick the easier one in this equation 8 + 1 = 1 + 8
, which is the one on the left. It's
way easier to add 8
to 1
, same goes for (8 + 5) + 5 = 8 + (5 + 5)
.
Isomorphic objects are treated the same by the rest of the category.
Depends what category you're in, Always make clear which context you're in, this is only happening in that context.
Abstracting is forgetting about data that isn't revelevant to the situation, not data that is relevant to the situation.
Lambda Calculus - Fundamentals of Lambda Calculus & Functional Programming in JavaScript (1:02:14)
Idiot (or Ibis) combinator (identity)
const I = a => a
In lambda calculus you have:
- identifier - defining a variables
- application - applies a function to arguments
- abstraction - defines a new function:
λa.b
in JavaScript isconst funx = a => b
- grouping - disambiguates operator precedence
In lambda calculus all functions are unary, take a single argument.
Beta reduction, scary name but it just means taking a function and applying it to its arguments. For example
((λa.a) λb.λc.b)(x)λe.f
(λb.λc.b)(x)λe.f
(λc.x) λe.f
x
So we fully evaluated the function, beta-normal form.
Mockingbird combinator (self application)
const M = f => f(f)
M(I) === I(I) === I
M(M) === never // maximum calls stack size exceeded
We don't know if some lambda term is going to have a beta normal form, if the process of reduction ends or not. Sometimes it does, sometimes it diverges. Halting problem.
Kestrel combinator (first, const)
const K = a => b => a
Kite combinator (second)
const KI = a => b => b
// which could be also written using the Kestrel and the Identity
const KI = K(I)(x)(y)
// x is dropped, K(I)(x) is I and I(y) is y
A combinator is a function with no free variables, λb.a
is not a combinator,
λa.b
is a combinator.
Cardinal combinator (reverse arguments)
const C = f => a => b => f(b)(a)
// the Cardinal of the Kestrel takes two things and returns the second
C(K)(I)(M) === M
// which is the Kite
KI(I)(M) === M
At this point the speaker seem to start talking about a subject similar to the one
exposed in programming with nothing, so true
is the K
estrel and false
is the KI
te.
These are called Church encodings.
Not = λp.pFT
which in JavaScript is const not = p => p(F)(T)
.
CtT = F
and CF = T
.
const and = p => q => p(q)(p)
const or = p => q => p(p)(q)
#HITBGSEC 2015 - Marina Krotofil - Hacking Chemical Plants for Competition and Extortion (1:02:26)
Industrial Control System (SCADA).
Cyber physical attack, an attack that gets launched in the cyber world that has effects in the physical world.
- what can attacker do with the vulnerability?
- any further actions required?
- how severe the potential physical impact?
Process control automation
Control loop: physical process - sensors - control system - actuators - physical process
PLC programmable logic controller.
Control logic: program in the PLC that defines what should and what should not happen.
PLC cannot control the processes on their own, they don't have the big picture. We need human operators.
HMI is the Human Machine Interface.
Why hacking SCADA? Money. Lots of. For example you could reduce product quality. Think about being paid by a competitor for that.
Stages of cyber-physical attacks
- Access
- Discovery
- Control
- Damage
- Cleanup
Security is about rising the cost of the attack.
Frank Abagnale: "Catch Me If You Can" | Talks at Google (1:03:09)
The talk itself is around 40 minutes long, but the Q/A part is also interesting.
One thing he said I wasn't expecting: it would be way easier to do now what he did because of how pervasive technology is; and people are still the weaker point in the system, a hacker waits for two things:
- for someone to do what they were not supposed to do
- for someone not to do something they were supposed to do
Making a 5 Shots Assassin's Creed Style Wrist Crossbow | Shooting (21:17)
I found the time lapse relaxing and full of little "ah-ha! that's how that's done!" moments.
Porch Pirate vs. Glitter Bomb Trap 2.0 (18:14)
When science is fun
Anjana Vakil: Learning Functional Programming with JavaScript - JSUnconf 2016 (29:56)
Anjana went to the Recurse Center as me, this was already interesting enough to give her talk a go. It's an introductory talk if you're approaching functional programming and want to know what it is about, with some examples expecially on map / reduce which instantly give you an idea. Tough croud though, didn't really reacted in any way.
Anjana Vakil - Immutable data structures for functional JS _ JSConf EU 2017 (26:32)
Because I've watched the previous one, and because she has the funny approach that reminds me so much of other fellow Recurse Center alumni. In half an hour or so she explains the theory behind immutable data structures. Doesn't explain why though.
Keynote - Why Functional Programming Matters - John Hughes, Mary Sheeran (Lambda Days 2017) (1:03:01)
This is one of those talks that give you lots of resources to expand the subject. They speak about how you should structure your code with functions intended as consumers and producers. What I've missed is examples, code examples you could start from to apply the concepts expressed in the talk.
You could "summarise" it like so:
- whole values
- combining forms
- simple laws
- functions as representations
If you don't know what that means you're not alone, this is what I meant when I said that this talk gives you lots of resources to expand your knowledge.
Rob Martin - Teaching functional programming to noobs in mobs (Lambda Days 2016)
Hire juniors. They inspire seniors to work better, they get trained and they can learn more than seniors usually do. Why learning functional programming? Because simplicity allows to:
- reason about code
- test code
- prove our code
- trust our code
Functional programming languages usually limit the power of the user, wink wink to Out Of The Tar Pit. In functional programming our state is exposed, if it's too complex, it's there as a parameter, so it's much easier to spot. Do everything you can without side effects, don't mutate variables, don't handle state (your state should be just in the tests), compose your functions, then, once you're done introduce side effects. So our business logic almost never depends on other libraries, while our side effects logic almost exclusively libraries so we don't have to run unit tests around them. He also introduces the concept of mob programming. I feel there's lots of wisdom pearls in how to manage a team.
Functional programming design patterns by Scott Wlaschin (1:05:43)
Whirlwind tour at high speed of several concepts.
Functions are things, not really attached to classes or objets, take something in and send something out.
Composition everywhere.
Types are not classes, they're just set of inputs and outputs to functions. A name given to a set of values.
Strive for totality: for every input there's a valid output.
For example in a function that divides 12
by the given input you could do this in two ways to avoid division by zero, and the dilemma
of having to throw exception or not:
- restrict the input with a type like
NonZeroInteger
that has all integers except0
- extend the output to be optional (
Maybe
monad)
Parameterise all the things.
I loved what follows, I really did, he basically started with interfaces, explained how they're a bit bloated and proposed types as substitutes.
Function types are interfaces, if you add the Single Responsibility Principle (only one reason to change) and the Interface Segregation Principle (don't contaminate interfaces with too many things) and you take that a bit to the extreme you get interfaces with just one function. But an interface with a single function is just a funtion type, and any function that has the same signature is compatible with it, and you don't have to inherit anything, it's automatic synce they share the signature!
Partial application, which is useful for dependency injection too allowing to bake in things like database connections.
Continuations, the Hollywood principle: don't call us we'll call you. Let the caller decide what's going to happen, passing in functions for example to deal with the division by 0 from above.
How to combine a function that outputs two different types with one that accepts just one? Bind all the things! (monadic bind)
Map allows you to stay in the world of options, so you could call functions on types that you're not sure what value they represent, think about
the result of an async call that returns a Maybe
, most generic wrapped generic types have a map
, use it! Functors are just mappable types.
Clojure Remote - The Elements of a Functional Mindset (Eric Normand) (43:51)
"The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise."
-- Edsger Dijkstra
You don't want to have side effects buried in the code, pull them out separating them calling the side effect function elsewhere and pass the result.
Functions should not depend on internal structure of data, pull out a new function that knows how to access fields in the data structure.
Distinguish what you calculate and how you calculate that something, pull out the structure into one place.
LambdaCast 1: Overview Of Functional Programming (1:13:36)
The panelists go through the basics of functional programming explaining how they apply to real problems using building blocks offered the paradigm:
- immutability
- higher order functions
- purity
- functions as first class citizens
- etc
I liked the general idea of having more experienced people on the podcast, along with people that just started looking into functional programming, that helps a lot in cover those things that might be take as granted when they shouldn't.
LambdaCast 2: Overview of Functional Programming part 2 (1:40:40)
In the first 30 minutes or so the panelists finish the topics of the previous episode.
A big part of the episode is about the "Simple made easy" talk from Rich Hickey, and how that relates to functional programming, for examples not having to think about side effects, not dealing with changing parameters, and so on. Pure functions, immutability, no side effects.
Distinction between side effects and effects.
Variables are such in a math sense.
LambdaCast 3: Why FP? (1:31:14)
null
presence considered a smell.
All functions are a single expression in Haskell and PureScript, so whatever you have in the body that's returned from the function, and that's completely different from you have in other languages.
Typesystems as a benefit and a friend rather than something you have to please to have your code work.
Good function: isolated, doing one thing, testable. Impure functions should have a small as possible surface area.
LambdaCast 4: Higher-Order Functions (48:39)
I don't have much to say here, all previous 3 episodes covered concepts I'm kind of familiar with... I didn't manage to extract much information.
LambdaCast 5: Immutability (59:38)
Referential transparency and explanation.
Immutability as a solution to multi threaded problems (locking, shared resources, ...), ref
in Clojure seems a good
approach to this problem.
Shallow copies and deep copies.
In immutable lists if you add elements to the head then you can keep on doing so without impacting anyone else that have a reference to the previous elements of the list. This passage is at 37:20.
So instead of "what does it mean to update and delete" we have "what does it mean to create a new state", we go from one state to the other.
LambdaCast 6: Null And Friends (49:19)
Introduction of Maybe
, along with Either
, to solve the null
problem. The latter could also help to replace exceptions or
chain stuff with lots of andThen
s. It basically lifts types to a higher state in which they could be used without worrying
about them producing a null
, because that's being taken care of.
LambdaCast 7: Recursion (43:45)
In a recursive approach you just pass new objects each time, as opposed to what happens with the mutation that happens
in a for
loop for example.
One downside could be that if you're not careful you could blow up the stack pretty easily.
LambdaCast 8: Morphisms (43:09)
Cathegory theory is the explanation of why and how math works. "Math of math". A morhpism is a function that takes a type and gives back a type, all pure functions are morphisms
- endomorphism is a function that takes a type
A
and returns a typeA
- isomorphism is a morphism that could be reversed, if you have
A
toB
you could go back fromB
toA
; it's more than just types, it's about the function inner structure, as some information could be loss when going in a direction. An example could going from aFloat
to anInt
: you can't go back as you've lost some information - homomorphism does not change the struction of your thing
- catamorphism goes from an algebra to another algebra, where an algebra is the set of operations you can do with your thing, an example is moving from logs to reports
LambdaCast 9: Polymorphism And Abstraction (1:23:51)
Introducing type parameters.
Introducing the concept of lenses.
"The more we know about the type, the less we know about the function; the less we know about the type, the more we know about the function".
Let's say we have a List Int -> Int
, what we can say about the function? Well, almost nothing, it can do a lot of things.
This is what I think they meant with the previous sentence. They go through a few different function signatures asking
"what can we tell about this function just by looking at the signature?", it's a powerful discussion that underlines
the importance of having parameters as types.
It's important to know that we know that when they say f
of a
f
is not a function, it's a type; it's not f(a)
.
If we were to throw immutability and purity away we couldn't think about functions the same way just by looking at the types, just because we won't have the same constraints.
Parametric polymorphism and polymorphism in object oriented are two separate concepts.
Introduced the concept of functor, which they explained as something that you could map
over. f
is mappable is the same
as f
is a functor.
Reusability of functions and polymoprhic types enable functions reuse, because the type is less specific.
"The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise."
-- Edsger Dijkstra
LambdaCast 10: Partial Application (1:09:51)
A function must be curried to be partially applied. In terms of parameter ordering you have what could configure the function coming first, then in the last position you want the thing you will act upon, for example you could configure a function to save an array to the database, the first parameter could be the connection, the second the query, and probably the last will be the array.
In languages like Haskell you see a function declared as add :: Integer -> Integer -> Integer
, one might read it as
"add
is a function that takes two integers and return an integer", but what that actually means is "add
is a function that
takes an integer that returns a function that takes an integer that returns an integer".
One could imagine a partially applied function as a screwdriver with a detachable head, so you have a function (the headless screwdriver) and then you have different heads you could attach to it (parameters) so it's configured for a specific task.
They then explain the difference between code that's dense and code that's complicated. Usually in FP you're doing multiple things on one line, that's more dense for sure, but maybe not more complicated.
LambdaCast 12: Monoids (1:05:33)
A semi-group is a data type that has an operation that takes two elements of that type and merge them together to give back an
element of that type. That operation is called append.
This operation obeys the law of associativity, so a
combined with b
and then combined with c
is the same as a
combined
with c
and then combined with b
.
Associativity is of particular help if you need to deal with a huge list for example, because you could use divide et impera.
Integers under addition are a semigroup, integers under multiplication are a semigroup.
A monoid is a semigroup with an identity value for that data type. So for addition it's 0
, for multiplication is 1
. For arrays
it could be []
.
By knowing this terminology problems could be lifted in a new space where everyone speaking could bring problems from their area of expertise into the discussion.
A function that takes an Integer
and returns an Integer
is also a monoid, it's composable.
In the monoid of functions that go from a
to a
the identity function is the identity value. It doesn't change the thing you're
composing with.
LambdaCast 14: Dynamic and Static Languages (1:17:02)
In statically typed languages the type lives on the variable, in dinamically typed languages the type lives on the value.
Benefits of dynamic languages: a team of developers from Naught Dog used hot reloading to speed up development time, writing a game on the PS. So the emphasis is on shorter development cycles.
The faster iteration could be seen as checking things in the REPL, really fast, with immediate feedback.
People tend to have fewer data structures with lots of functions acting upon them.
Benefit of static languages: a strong type system allows you to think about the type that you're wrtiing and building up with those, helps you add more and more functionality with the guarantee that the application still works as you progress.
You write types, lots of them, and the implementation is trivial in the end, because the amount of detail that has been added is so great that actually the compiler can even write portions of the implementation for you (Idris does this).
About abstractions: for a function that A -> A
, the only thing you can say it's that is the identity function because you
don't know how to construct an A
and without side effects and global state there's no place you could pull that knowledge
from. So types helps you by restricting the amount of things a function can do.
The compiler is there to help, it's not anymore something that you have to keep happy, you want to leverage the help the compiler gives you.
As a final thought one might say that the time spent in the REPL in dynamic languages is somewhat "lost"; on the contrary time spent building types remains in the code.
Plain Functional Programming by Martin Odersky (46:57)
Greatest difficulty in software engineering is complexity. Software systems get replaced not when they wear out but when they crumble under the weight of their own complexity.
FP helps by removing one important dimension of complexity: the need to understand the history of the program in order to understand a single part (a function). Functions just take parameters and give you a result, no side effect.
The functional way: parameterize all the things, even though it could have problems, for example having too many parameters.
Raise your abstracts. Category theory.
The great thing in this video is the second part, where Martin Odersky goes through a real world example on how to use types to make code more adherent to FP principles.
He introduces the notion of Algebraic Effects.
From Javascript to Haskell : Functional Programming made simple - Voxxed Days Singapore 2018 (50:04)
Audio of one of the two speakers is horrible, adding some noise from the audience makes the video difficult to understand, I just followed their actions on the code to understand what was going on. And it's a shame, the content realle seemed high quality!
They start with a function that searches for movie titles in a movie database.
First pass: extract functions from the bigger one to name steps, leave the while loop untouched.
Second pass: extract movie database fixture from tests into a variable to reduce duplication, this highlights the fact
that in the function they're modifying the array. Used for (let element of elements)
to remove the problem.
Third pass: add type signatures on top of functions, as comments.
"If you have a function that returns nothing that's either a) useless or b) containing side effects."
Fourth pass: moving the side effects to the edkges of the application.
Fifth pass: syntax allows for more succint code.
Stopped around min 30, as the other speaker started a solo that lasted more or less the rest of the talk, too difficult to understand.
How is this speedrun possible? Super Mario Bros. World Record Explained (27:00)
Behind a world record speedrun there's more than just smashing on a controller, there's careful planning and knowledge about how the game works almost at the code level. For example the current WR holder uses how the game stores the destination of where the pipes send Mario to its advantage saving time.
The explanation of this part is incredible, tells you exactly how precise you have to be not to lose a precious frames, and why. As I've understood it Mario the game has some optimisations that you exploit to move faster in time, looks to me that you can actually shrink space by jumping on the correct pixels.
It's all about pixels and when you're towards the end of a run, a pixel in difference can ruin your whole run.
Bloodborne Speedrun in 34 Minutes (33:09)
The fact that he made the run in less than 33 minutes without even dying once, and, with an underlevelled character is baffling.
Fascinating how monsters react in a different way when you approach them head on: almost no one of them attacks, and with bosses, if you know where to hit them, a fight that easily took me 20+ retries could be done at the first attempt (by him of course), in less than a minute.
Especially with Amelia, damn I got stuck fighting her for so much I almost stopped playing the game; probably this is the good thing of Bloodborne: the satisfaction you get when you slay a prey after all those retries.
Nara Kasbergen: Empathy as a Service: Supporting Mental Health in Tech | JSConf Iceland 2018 (33:29)
1 in 5 adults suffers from mental health issues. Not so many people talking about.
People affected by mental health issues often hears "I can't believe you're depressed when kids in Africa are starving". There's an answer for this: "Telling someone they can't be sad because others have it worse is like saying someone can't be happy because others have it better".
A questionnaire used to gauge the situation had a question like
- "Do you think that discussing physical health with your employer would have bad consequences?"
- "Do you think that discussing mental health with your employer would have bad consequences?"
Usually there are lots of no in the first and lots of yes in the second.
Being aware of mental helath is especially important if you're a remote worker, after the first couple of months of wonderful realisations, people find they're missing discussions with colleagues and all the social interactions that happen in the workplace. Some things the employer could do to mitigate the problem include but should not be limited to:
- paying for a month of coworking space, to see if the employee can benefit from that
- have recurring meetings where everyone meets up
Decorating your workplace is a really helpful thing to do, it makes it more yours.
Empathy is the antidote to shame. From this comes the title of the topic: everyone should offer their empathy to others.
Dependent Types in the Idris Programming Language 1 - Edwin Brady - OPLSS 2017 (1:17:25)
Edwin introduces the concept of Type Driven Development, which he also explains in Type Driven Development with Idris; type define refine as opposed to red green refactor.
One thing in common with Test Driven Development, it's about deciding what you're going to do before you do it. Types are a mean by which you tell the machine "this is what we are going to work on together", it's a dialog with the machine. Types are first class citizens as functions are in functional programming languages.
You define functions by recursively defined equations.
In type driven development you
- write the type
- add the definition
- split case of the hole name
You coudl also search for a possibile implementation with the proper command.
"Just because you have types doesn't mean you can't add more tests, and you should add more tests."
Look at type holes for hints on how to proceed.
Build functions one bit at a time leveraging the compiler can help you with the types of your holes.
Lowercase letters in types are always implicitly bound.
As soon as you have something a bit hard to do, make another function to do that harder thing.
miniKanren Intro Series #1 (2:06:25)
I think it's safe to say that if you know a Lisp you could skip this first video.
miniKanren was originally written as an extension of Scheme, and allows for logic programming.
There's also microKanren which is a simplified version, 51 lines of Scheme!
The point is to have a very small language, built around 3 or 4 operations, much like Chess or Go, and from there build new things and think about the system.
William then names the most used Lisp dialects, talks about the benefits of macros, and briefly explains the history of Scheme and Racket.
What follows is an explanation of the basics that could be found in a Lisp dialect, and later in Scheme.
Meta circular interpreter, implementing Scheme in Scheme, is what we will do later on in this series.
list?
is pronounced as "list-uh?".
One thing he pointed out is that you could have something like
(cond
[(= 1 0) 'a]
[(= 0 0) 'b])
to highlight the clauses.
miniKanren Intro Series #2 (02:27:09)
If you went through The Little Schemer you're going to remember some of the examples he makes.
Building up recursive functions following test cases is a helpful technique to help
yourself when your're stuck not really knowing how you're going to build up the
result, for example in member
you could use
(member 'x '()) ;; #f
(member 'x '(a x f x g)) ;; #t
(member 'foo '(a foo g)) ;; #t
and then build from there the base case (first line), the case in which you've found a thing you were looking
for (second line), and the recursive step or else (third line).
As William said earlier you could even pretend you have your function (whishful thinking) and then use
it to fill the gaps, only to go back later to actually code it, in the videos he names such functions as
dans-member
if, for example, he was midway coding member
; it's called dans-
as in Dan's referring to
Daniel Friedman.
He then talks about map
and filter
.
The discussion then changes to quotation, so:
- quote
'
- quasiquote ```
- unquote
,
- unquote-splicing
,@
Another interesting point he makes is that
(let ((x 7))
x)
is the same as
((lambda (x) x)
7)
Macros and define-syntax
are next.
Small introduction to lambda calculus closes the video.
Bach - Goldberg Variations - Andras Schiff (1:16:15)
The Goldberg Variations, BWV 988, are a work written for harpsichord by Johann Sebastian Bach, consisting of an aria and a set of 30 variations. First published in 1741, the work is one of the most important examples of variation form. They are named after Johann Gottlieb Goldberg, who may have been the first performer.
Noam Chomsky on Democracy Now! April 4, 2017 (FULL Interview) (1:11:42)
I love how Chomsky talks about what he calls the two tiered system: Bannon-Trump team dominates the headlines, so whatever they do that's what people look at, one crazy thing after the other make the headlines, and by the time the new one arrived the old one is forgotten. And while this goes away things like the EPA slash could be safely made behind the covers.
They proceed talking about Russia interfering with US elections, the Russian border, and North Korea tensions.
"Why are they developing nuclear weapons? It's a deterrent." North Korea will terminate its further development of nuclear weapons, in return the US should stop threatening maneuvers on the border. "If the US did decide to use force against North Korea, [...] Seul (confused) be wiped out by mass North Korean artillery".
Nort Korea was destroyed by the most intensive bombing in history, they flattened the country, leaving no targets left. Then they attacked the dams, which is a war crime of course. On the subject
Doomsday clock set at 2min 30sec.
Nuclear weapons and Global Warming both are questions of survival and should be the main focus of attention, every Republican candidate through the election either denied or said we shouldn't do anything about it.
The Sanders achievement, usually "You can pretty well predict electoral outcomes simply by campaign funding alone", is remarkable as it represents what could happen if just policies are presented, which meet the concerns of the population.
Trump is not going to bring back jobs, what happens then? Something has to be made to maintain control, so scape goating could be an option, then an alledged terrorist attack, or a staged attack of minor kind. "It's very easy to terrify people".
Iran has very low military spending, even compared to the region standard (Saudi Arabia, Israel, ...) they want to deter attacks. If they are developing nuclear weeapons is for their deterred strategy. "Who's concerned about a deterred? Those who want to use force. [...] So yes Iran is the greatest threat to world peace".
Mortality is increasing amongst low and middle class working class middle aged white americans, that's something unknown in developed society, it's something called Disease of Despair: there is no feeling of hope in the future or sense of dignity.
Martin Luther King – Beyond Vietnam: A Time to Break Silence (56:37)
The audio player found at the above link seems to work only on Chrome.
"A time comes when silence is betrayal."
"For we are deeply in need of a new way beyond the darkness that seems so close around us", this is so in line with what's happening these days (early September 2017) between North Korea and US (again).
"And I knew that America would never invest the necessary funds or energies in rehabilitation of its poor so long as adventures like Vietnam continued to draw men and skills and money like some demonic, destructive suction tube. So I was increasingly compelled to see the war as an enemy of the poor and to attack it as such." which is the same thing one asks themself when questioning Trump's actions these days, is being so belligerant going to help Americans? Is being openly hostile towards people near US south border going to be any good in the long term?
"So we have been repeatedly faced with the cruel irony of watching Negro and white boys on TV screens as they kill and die together for a nation that has been unable to seat them together in the same schools. So we watch them in brutal solidarity burning the huts of a poor village, but we realize that they would hardly live on the same block in Chicago. I could not be silent in the face of such cruel manipulation of the poor."
"Those who make peaceful revolution impossible will make violent revolution inevitable." John F. Kennedy.
"One day we must come to see that the whole Jericho Road must be transformed so that men and women will not be constantly beaten and robbed as they make their journey on life’s highway. True compassion is more than flinging a coin to a beggar. It comes to see than an edifice which produces beggars needs restructuring".
Object Oriented Programming vs Functional Programming
Interesting take on the usual debate. OOP is much more about passing messages between objects and let them react (polymorphism), rather than about inheritance.
Cosmos - A Spacetime Odyssey
From Neil Degrasse Tyson, I love the series. It's not fun-oriented but they keep it interesting at every episode. Also Neil's voice is pretty calming.
Inside Black Holes | Leonard Susskind (1:10:32)
I am not sure why I watched this video, I think the title and the fact that it looked sciency prompted me to. I didn't get most of it, but it's fascinating listening to someone talking about their craft. It's particularly fascinating how he describes a black hole as seen by an external viewer, picturing it as layers and layers of sediments consisting of things that got attracted and never made it past the even horizon; and also how it takes a finite amount of time to fall through the horizon for an in flowing observer and an infinite amount of time as seen by the outside. There's lots of information near the horizon! One of the things I probably misunderstood the most is that distant Hawking radiation could be a description of the interior of a black hole, which sounds amazing.
How Earth Moves (21:37)
Micheal (VSauce) explains the difference between a sidereal day and a solar day; this video is packed of information but a few interesting things are clear without turning to Wikipedia, for example that the Earth follows an elliptical orbit around the Sun. A clear explanation of seasons and leap day could be found in the video, but it's really the introduction of the Gregorian calendar that seemed really interesting. Phenomenal closing though about "THE ride of your life".
Why Alien Life Would be our Doom - The Great Filter (9:35)
Where they explain why it would be bad for us to discover ruins of a civilization on Mars.
They also offer a few answers on the Fermi paradox.
Quantum Computing Expert Explains One Concept in 5 Levels of Difficulty | WIRED (19:27)
Super position and entanglement.
Shows a spinning coin and explains how you don't know whether is heads or tails. If you have two which are spinning and entangled then if when stopping one it turns heads then also the other one is going to turn heads.
She spent increasingly larger amount of times as the level of education of the other person increased. I would've loved each session to last the same amount of time, describing the same things with the most effective words for each person.
There are two big challenges
- fault tolerance
- amount of operation you could do before time runs out and you lose the information about what you were doing
C_C++ in Spacemacs (40:22)
I watched this video because I want to understand what the start of the art is when coding C++ in Spacemacs.
The tip to use C-u to speed up compile time looks great.
Indentation wise he speaks about cstyles, C-c ,
asks for a style. He goes a lot talking about indentation, since
the team I'm in has its own, or I'm not sure which major one they adhere to, I just moved fast through this section.
For autocompletion there's clang, the de facto standard, which could easily be enabled in Spacemacs.
He skipped debugging and ctags, which I would've loved to hear about though.
NOTES FOR SELF:
- command to compile
- with c-u you can have more processes to compile, maybe use that to speed up compile time?
- autocompletion is not working in your conf, check it
Guillaume Néry: The exhilarating peace of freediving (19:14)
A poetic view of what both body and mind experience during a freedive towards 123 meters below the surface. Give a few insights on how a freediver prepares for the descent and what they experience during it.
Tanya Streeter | TEDxAustin 2012 (16:58)
I was fascinated by the previous one and impressed by the story of Audrey Mestre I got to know after that, where Tanya appears briefly, so here I am with another video about the same sport.
She speaks how she beat women, and men, in this discipline. The dive takes 3:30 minutes to 4:00 minutes. She speaks about the "packing" technique, and how this led her to black out. Narcosis still affects freedivers because of the rapid rate of descent and the extreme depths they go to.
She then speaks about what happened with her daughter being born.
Then moves on talking about plastic and the sea, and about giving back to it. Referencing a film called "Plastic Ocean".
How to Hold Your Breath Longer: a freediving tutorial from a professional freediver (10:20)
Tips on how to hold your breath and getting good at it, introduces training tables (CO2 tables or O2 tables). Also explains how to get started towards the end of the video.
The Three Laws of TDD (1:06:08)
It's an introduction to TDD, with some theory and some examples on how to use it.
- You are not allowed to write any production code unless it is to make a failing unit test pass
Which means you have to write the test first.
- You are not allowed to write any any more of a unit test than is sufficient to fail; ad compilation failures are failures
- You are not allowed to write any any more production code than is sufficient to pass the one failing unit test
Unit tests as examples of how your code works. If you write the tests first it's impossible to write a function that's hard to test, functions are written to be easy to test. The goal of TDD is to create a test suite such that when it passes you can deploy. A reliable test suite that passes allows you to make decisions.
TDD is a way to incrementally derive solutions to problems.
'Uncle' Bob Martin - 'The Future of Programming' (1:18:20)
"Why is it that we programmers are never happy with our language?" "Why is it that our industry is so incredibly male dominated?"
Number of developers doubles every 5 years, and there are not enough experienced people to teach the new generations, this is because a great portion of the total is composed by young developers. So it looks like we are doomed to repeat our errors over and over.
Bob Martin lived 22 orders of magnitude of growth in the hardware. Software hasn't changed that much: you would recognise the code that Alan Turing wrote in the ACE machine, you wouldn't like it, but you would recognise it. You could bring a PDP8 programmer into the present and put them in front of Intellij to code Java. Our advancement since 1945 is almost entirely about what not to do than what to do:
- structured programming: don't use unrestrained GOTO
- functional programming: don't use assignment
- object programming: don't use pointers to functions
The last 15-20 minutes are particularly interesting, where Bob Martin explains how "we kill people" and how "we rule the world", and what we could do to limit problems.
John Carmack's keynote at Quakecon 2013 part 4 (29:59)
John Carmack talks about a few concepts, particularly interesting for me were
- functional programming - functional style allows for self contained code, because it's all about passing something in and getting something out, the advanteges of writing code in pure form are a big win especially in the long term
- Haskell - brutal purity of Haskell [...] multi paradigm as if its a good thing, but it means you could always do the bad thing if you feel you really need to, and programmers are extremely bad at doing sort of the time scale integration of the cost of doing something that they know is negative [...] how many times this little bad thing is going to affect them
- Lisp
- Scheme
- strong and weak typing - everything that's syntactically legal, and the compiler will accept, will eventually wind up in your code base and that's why static typing is so valuable because it cuts down on what can make it past
Rails Conf 2012 Keynote: Simplicity Matters by Rich Hickey (36:52)
Simple - one fold / braid Complex - combine together many things / braid them together Easy - to lie near, at hand
Simple is about interleaving not cardinality: not one thing (ex interfaces with one function) but one role / task / concept / dimension.
Elephant of complexity represents the difficulty in maintaining your code.
Simplicity buys you opportunities, it dominates all other factors. Once your project reaches a certain size the complexity elephant dominates all other techniques you might be using, tests, agile, nothing will help you pushing the elephant away.
Pursuing simplicity is about pursuing opportunity.
Examples of simplicity in context:
• order should not matter • information is simple, don't put stuff around those, hashmaps are fine • take approaches from sub systems architecture and use them into code
Simplicity is a choice. Requires vigilance, sensibilities, and care. "Did we entangle anything yesterday? Did we complect anything yesterday?".
Mark Allen - The Sharp Edges of Leaky Abstraction (37:26)
The Law of Leaky Abstractions by Joel Spolsky mentioned in the video.
When is an abstraction leaking? What does it mean?
Exposing internals.
An example: a specification which is short and understandable but doesn't completely describe the behaviour of the software, and then you have a more complex one which "in this particular case it doesn't work like that", you have to do extra things to fix it up. When you have these two, and you want the simplest one but the second one is the one that's implemented that's the leak.
Here's the moment in the video where this is explained.
What things cause us to create leaky abstractions?
GOTO 2017 • A Crystal Ball to Prioritize Technical Debt • Adam Tornhill (50:09)
Basically this talk gives you the tools necessary to answer the "Should I address technical debt? If so, where?".
Adam proposes a way to decide when and where to tackle technical debt. He talks about how git, thanks to its informations about code changes over time, can point the developer to where an action is mostly needed.
Here he shows an interesting pattern shared by three radically different codebases.
He then speaks about normalization of deviance, or how people come to accept what they experience in their every day lives.
Types, and why you should care (1:04:05)
Speaker is Yaron Minsky, the one who brought OCaml into Jane Street.
- values - data that flows around in your program
- variables - a name that points to a value
- expressions - a collection of syntax that has some meaning
- types - cathegorisation system for values, grouping related values together
In untyped languages values have types, while in typed language values variables expressions have types.
var x = 5; // value has a type in JavaScript
int x = 5; // variable and value have a type in Java
Statically typed languages, the code that you wrote (the text) has a meaning associated.
Types help communicating intentions and in detecting errors.
There's also a discussion on HN about this.
Notes on Type Theory for beginners (48:26)
"What is a type system?"
In all la guages we have
- Data
- Operations Not all available operations make sense to all kinds of data. "If you use incompatible pieces of data for your operations you will get a representation error".
"Programming languages use a type system to look at a program and determine if a representation error will happen or not".
What strategies could we use to handle those representation errors?
Well you could:
- perform a type check before running the code - Java - Strong
- have unpredictable error set and implicit conversions - JavaScript - Weak
- tag code and try to infer if the behaviour will be correct or not - Static
- generate code to keep track of the data - Python - Dynamic
A Hitchhiker's Guide to the Functional Exception Handling in Java by Grzegorz Piwowarek (38:02)
Exception handling like a goto statement, unexpected exit point.
Go for example doesn't throw exceptions, it returns them, because you can actually returns more than one result from a function.
One should construct a type safety stronghold, and from there to rule over everything!
Instead of doing
List<Url> getSearchResults(String searchString) throws IOException { ... }
one might want to do
Try<List<Url>> getSearchResults(String searchString) { ... }
and then
getSearchResults("foo")
.map(...)
.filter(...)
.onFailure(ex -> LOG.info("..."))
.recoverWith(...)
.getOrElse(( -> 42);
This is the "Try" library he showed.
He proposes the use of Either
type instead of throwing exceptions, which is a type that could have one or another value
but not both. He then speaks about projections to be used with Either
; so in the end we would have
Either<FetchError, List<URL>> getSearchResults(String searchString) { ... }
// and then use it like...
result.right() // right projection
.filter(...)
.map(...)
.getOrElse(Collections::emptyList);
// ...or...
result.left() // left projection if you're interested in the error
.map(FetchError::getMsg)
.forEach(System.out::println)
Use exceptions when you don't expect people to recover from them, so for exceptional situations!
"To Try or not to Try, there is no throws" -- Yoda
A Pragmatic Introduction to Category Theory - Daniela Sfregola (40:31)
From the same speaker: A Pragmatic Introduction to Category Theory—Daniela Sfregola - (1:16:35)
A category is two objects and an arrow that connects them, objects could be anything. Objects are types and arrows are functions.
You have three properties that come up often:
- composition
- identity
- associativity
She talks about monoid, which has a way to compose two things of its type and produce a thing of the same type and knows that the identity for that type is.
Functors as boxes that can unwrap what they contain.
Combining two boxes into one gives you an applicative, every applicative is also a functor.
Fusing two boxes together is a monad.
The take away from the talk seems to be: forget about the details, category theory is about how things compose.
"Propositions as Types" by Philip Wadler (42:42)
Computer is a person following a sequence of instructios
He makes the example of three notable scientists (Hilbert, Gödel, Turing), then asks "Is mathematics invented or discovered?", given that those three arrived to the same conclusions to the "decision problem" independently one could argue that it's discovered.
Propositions as types: Propositions in logic -> types in a programming language
Proofs in logic -> programs in programming language
Simplifications of proofs -> evaluation of programs
Curry-Howard correspondence
- propositions as types
- proofs as programs
- normalisation of proofs as evaluation of programs
Dependent types are at the core of languages used to represent proofs.
"Most of you use programming languages that are invented. And you can tell!
[laughter]
So my invitation to you is to use programming languages that are discovered."
He really puts an emphasis on following things that are discovered rather than invented.
Propositions as Types - Computerphile (17:45)
Relation between proofs and propositions, and programs and types.
The evidence of a proposition is the type of its proofs, whenever you find an element of this type you've verified the proposition (more or less, I am not sure I am grasping this).
An Introduction to Refinement Types (29:46)
(sound is quite bad due to a constant noise in the background)Good languages make it difficult to shoot yourself in the foot, but you can still shoot yourself in the foot.
Well typed programs can go very wrong.
Refinement types = Types + Predicates
PLSE Seminar Series Ranjit Jhala, "Refinement Types for Dynamic Languages" (1:04:14)
The programmer tells what they want to analyse, so types, null pointer, array bounds, information flow, assertions.An example of a refinement type: { x : b | p }
, where
x
is the value nameb
is the base typep
is the refinement
Read as "set of values x
of type b
such that p
is true
".
How to analyse reduce
and describe its behaviour also as a refinement type?
Given this reduce
example type signature function reduce <A, B>(a: A[], B, (B, number, A) => B): B
we can enforce that
number
, second parameter of the iterator, is a valid index of a
, as such
function reduce <A, B>(a: A[], B, (B, idx<a>, A) => B): B
.
Refinement types = Type analysis + Value analysis
Challenges about implementing refinement types
- dynamic types
- assignments
- mutations
Dynamic types -> value based overloading
First a run of the typechecker is made, then we can decorate with the refinement types. Value analysis builds on top of the type analysis.
What's New In TypeScript (1:00:36)
.d.ts
files are called declaration files.
TypeScript targets EcmaScript 5. So for example arrow functions are compiled into regular functions. But it's a configuration setting that could be changed int tsconfig.json.
Exhaustiveness checking is introduced later on after some examples where he discusses a possible functional
approach to the usual Shape
, Rectangle
, Circle
, Square
OOP scenario.
Documentation pops automatically up when including a library and having its declaration files with type definitions.
"Understanding TypeScript's Structural Type System" by Drew Colthorp (37:46)
No need to speed the video, the speaker already goes super fast on his own!
Brief introduction of what TypeScript is.
"What is a type system? A logic system that derives constraints from code structures and reasons about them systematically to find inconsistencies."
"Turn a 2am production error into a red squiggle in our code"
TypeScript has a structural type system.
Nominal type system -> secret club you need to be invited to Structural type system -> as long as you meet the minimal requirements you can enter
type Point = { x: number, y: number }
type Named = { name: string }
type NamedPoint = { name: string, x: number, y: number }
NamedPoint
can be used anywhere Point
or Named
is expected. A better approach would be
type NamedPoint = Point & Named
(and
ing together the requirements of both types).
Type-level programming.
const ident = x => x // value-level
type Ident<T> = T // type-level
const pair = (x, y) => [x, y] // value-level
type Pair<T, U> = [T, U] // type-level
Towards the end the speaker wonders if the type system is Turing complete or not, well: microsoft/TypeScript#14833
Sequelitis - Mega Man Classic vs. Mega Man X (19:52)
This video is all about UX. It's a definition of UX.
The game teaches the player how to play through its level design.
The designers want to feel justified when you got hit. It's your fault, not theirs.
Conveyance. Theming. Fuck.
Angular the Redux Way by Gion Kunz (48:42)
State is your enemy.
Persistent state - storage, db, cookies, session Transiente state - url state, ui state
Flux data architecture: Action (dispatched from the view) -> Dispatcher -> Store -> View -> Action. It's a very controlled way on how to manage your data, it's unidirectional. Redux is an implementation of Flux.
Flux
- centralised state
- unidirectional
- reducers are pure functions, state transitions can be reproducers at any time
- simple to reason about
To deal with async calls one could use ngrx effects.
Common state patterns:
- async operations with error handling -
loadSuccessAction
,loadFailedAction
which are reducers handled like events - optimistic update
- load more button / infinite scrolling
- process steps / state machine - easily handle that in the reducer
Getting Started with Redux (2:01:25)
Here are some notes on the course.
Redux: The Single Immutable State Tree
This is the first principle.
The state describing all of the application, including the data and the UI state is represented as a single JS object, all mutations and changes of state are explicit.
This is the second principle.
The state tree is read only. When you want to change it you dispatch an action, which describes the change, it is the minimum representation of the change.
Only requirement is that has a type
property.
Pure functions
- return value depends just on inputs
- no side effects
- just calculate the new value, if you call them with the same argument you will get the same result
- do not modify arguments
This is the third principle.
UI is more predictable when it is described as a pure function of the application's state. State mutations in Redux are desxribed as pure function, argument is the previous state and action, and return the next state of the app.
If the reducer receives undefined
as state it must return the initial state of the
application.
createStore
accepts a reducer and creates the store.
Store holds current application state, lets you dispatch actions.
getState
retrieves the current state.
dispatch
dispatches actions to change the state.
subscribe
register a callback any time an action is dispatch
ed.
const counter = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
const createStore = (reducer) => {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
};
};
dispatch({});
return { getState, dispatch, subscribe };
};
const store = createStore(counter);
const render = () => {
document.body.innerText = store.getState();
};
store.subscribe(render);
render();
document.addEventListener('click', () => {
store.dispatch({ type: 'INCREMENT' });
});
To avoid mutation one could you Object.assign
, Object.freeze
, ora a library like
Immutable.js.
All reducers should return the current State.
It's ok to call reducers from other reducers, try to build them so that you can call them by passing the current state and an action.
"Redux: Architecting and scaling a new web app at The NY Times" by Juan Carlos Montemayor Elosua (41:16)
app = ui(state)
UI comes back to life once given a state, looks like this process is called hydration in Redux lingo.
Pure functions do not depend on other things generally (also kind of said by Martin Odersky).
3 principles in Redux:
- single source of truth
- State is read only
- State changes are made through pure functions
Views -> Actions -> Reducers -> State -> Views -> ...
Views - user doing something Actions - side effects Reducers - update the State
He introduces the concept of selectors and derived data, the goal is to have a small State, so you use functions to fill in
the gaps, for example if you need to show the username
which is name
concatenated to surname
, you don't store
username
, you store only name
and surname
and compute the other whenever needed.
Personal doubt: how much data should I put in the Redux store? Do you put everything in there? Do you put things you don't
need in the localStorage
and then put them in the State when needed? Here's one take from the creator of Redux.
Selectors remind me about lenses.
Set aside a place in your app to deal with side effects, or impure functions, as far as possible from the rest of the application. If something wrong happens you possibly know at this point that it might be dirty thing, you can point your finger basically.
Middleware in Redux can help you deal with side effects, so imagine that before and after the reducers, so you can massage the data.
These are the channels where I get most of my sources:
- alter conf
- clojure tv
- codegram technologies
- cognitect blog
- curry on
- deconstruct conf
- devoxx
- elixir conf
- erlang solutions
- freakonomics
- goto conferences
- jsconf
- lambda cast
- lambda conf
- lambda world
- mike stay category theory
- nordic js
- oredev conference
- reply all
- strange loop