God send!! The FP learning resource is quite sparse on the internet. I’ve been looking for structured material like this for a while.
15-150: Principles of Functional Programming
121–130 of 146 posts
Re: 15-150: Principles of Functional Programming
#122Earlier quoted context omitted.
Oh yeah, a pure function that accepts previous state, and returns the new state is the pattern I use a lot. The issue is that it is hard to do on complex graph structures in an algorithm where incremental changes happen to the graph O(n) times - it ends up creating complex code and complex execution that might be slow to pass the time limit on Codeforces, let's say. In the OCaml world maybe this is the place where yo…
Oh definitely go deep into monads. If you use the ST monad to do mutations, some people think Haskell provides nicer syntax to do imperative programming than traditional imperative languages like C. But of course such nicer syntax only comes from understanding and using important abstractions like monads, foldable, or traversable. Then there are niceties like automatic SoA/AoS transformation using type families.
Re: 15-150: Principles of Functional Programming
#123Earlier quoted context omitted.
let* permits expressions on the right refer to arbitrary other symbols bound by the let*. in particular it allows for construction of recursive lambdas that may not be linearlizable.
> let* permits expressions on the right refer to arbitrary other symbols bound by the let* In what language? I just checked Elisp, SBCL, and Guile, and they all error out if you refer to a variable not previously defined by a left-to-right traversal of the varlist: (let* ((a (+ b 1)) (b 1)) a) Edit: This doesn't work either: (let* ((a (lambda () (+ b 1))) (b 1)) (funcall a)) ; (funcall a) -> (a) for Schemes
(define-macro (let* bindings &rest body)
(if (null? bindings)
`(progn ,@body)
`(let (,(car bindings))
(let* ,(cdr bindings)
,@body))))Re: 15-150: Principles of Functional Programming
#124My complaint with FP: Sometimes I just want to do something silly, like adding a log somewhere. If I choose to add said side effect, now all my functions are marked with an io signature (so there might be _other_, nastier side effects hiding there as well - mainly an issue if you have multiple people contributing to the same project). If I don't add the side effect, and choose to refactor multiple layers of code, I w…
You got the wrong idea. You're supposed to write FP in a way where the side effect is highly layered and segregated away from pure code. IO are singularities within your chains of pure function compositions. As soon as you hit a singularity you have to break out of it as soon as possible.
The main idea is the meat. Keep your bread tiny and keep it very very separate from the meat.
The pattern is called Imperative Shell, functional core. Think of your IO as two pieces of bread in a sandwich and your pure code is the meat that connects the read to the write.
The game you're playing with haskell is to avoid letting the IO monad pollute any of your logic as much as possible.
Anyway that being said in applications where IO is all over the place... this pattern becomes largely ineffective. You basically have more bread than meat.
Re: 15-150: Principles of Functional Programming
#125on the choice of language to teach the course why sml i think there are a lot of nicer choice OCaml , its basically sml only more popular and used more in real life Haskell , again more popular , and used more in real life Idris , newer and said to be more progressive F# , a more practical choice and similar to sml a lisp , well if you want to focus on the functional part and less on the types part
because SML is awesome, isn't going to change and is simple. you can learn the syntax in an afternoon, and really focus on learning FP semantics.
Yes, I agree broadly with the line of thinking that says- if you are learning FP, you must be willing to do these, but a beginner might be disheartened and turned away- especially as someone learning alone.
Re: 15-150: Principles of Functional Programming
#126Earlier quoted context omitted.
He is probably talking about namespaces. In common lisp, for example, (a a) calls a function 'a' on a variable 'a'. Lisp knows this because the first thing that comes after the left paren is a function
more importantly there are functions (using scheme as an example) like set! and set-cdr! that mutate existing values and totally break referential transparency. this isn't just user facing - for example let* kind of depends on creating bindings up front so they work across clauses, and then mutating them afterwards
https://www.lispworks.com/documentation/lw70/CLHS/Body/s_let...
Re: 15-150: Principles of Functional Programming
#127Should have at least differentiated between "functional programming" and "pure functional programming" IMHO.
Re: 15-150: Principles of Functional Programming
#128My complaint with FP: Sometimes I just want to do something silly, like adding a log somewhere. If I choose to add said side effect, now all my functions are marked with an io signature (so there might be _other_, nastier side effects hiding there as well - mainly an issue if you have multiple people contributing to the same project). If I don't add the side effect, and choose to refactor multiple layers of code, I w…
Re: 15-150: Principles of Functional Programming
#129Great resource! Forgive my ignorance but why do so many modern functional programming courses use Standard ML instead of a Lisp dialect? Is it because of its built-in type-checking, or is it just how it's always been taught?
The value of purely functional programming languages, as opposed to functional programming languages like lisps, is that you get referential transparency, which means that when you define `a = b`, you know that you can always replace any instance of `a` with `b` and get the same answer. This is a very natural property in mathematics (algebraic rewritings are basically just this property writ large) and so it helps to…
The second is that languages like Lisp, SML, C, Pascal and BASIC all have referentially transparent and referentially opaque positions in exactly the same way that languages like Haskell do.
This means that all these languages enjoy referential transparency in the same way, because when you unpack the notion of equivalence, referential transparency itself is within a whisker of being a tautology: if a is equivalent to b, then you can substitute a for b or b for a. The relevant sense for "is equivalent to" can really only be contextual equivalence, which is all about meaning-preserving substitutability.
That said, not having to reason about effects within one's program equivalence sure makes things simpler in a pedagogical setting. But that's not to do with referential transparency per se.
Re: 15-150: Principles of Functional Programming
#130Earlier quoted context omitted.
Why does `let*` need to have mutation? It can be nested `let`s.
let* permits expressions on the right refer to arbitrary other symbols bound by the let*. in particular it allows for construction of recursive lambdas that may not be linearlizable.