return to table of content

15-150: Principles of Functional Programming

agomez314
20 replies
22h2m

Great 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?

johnday
13 replies
21h40m

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 draw nice parallels between the familiar notation of functions from mathematics and the "new" and "confusing" notion of functions in functional programming and other declarative languages.

As other posters have said, strong typing is also a nice property for lots of reasons, most notably it gives a platform to talk about ad-hoc and parametric polymorphism.

(I lecture on Functional Programming at the University of Warwick, where we use Haskell.)

albedoa
10 replies
21h23m

For those of us who are unfamiliar with Lisps, can you expand on how they break referential transparency (and how Standard ML contrasts in that regard)?

medo-bear
8 replies
20h59m

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

convolvatron
7 replies
19h40m

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

amake
5 replies
15h6m

Why does `let*` need to have mutation? It can be nested `let`s.

convolvatron
4 replies
14h59m

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.

tonyg
1 replies
8h27m

You're thinking of letrec.

amake
0 replies
8h16m

Ah, that does look to be the case. I didn't know about that one.

    Signature
    (letrec BINDERS &rest BODY)
    
    Documentation
    Bind variables according to BINDERS then eval BODY.
    
    The value of the last form in BODY is returned.
    Each element of BINDERS is a list (SYMBOL VALUEFORM) that binds
    SYMBOL to the value of VALUEFORM.
    
    The main difference between this macro and let/let* is that
    all symbols are bound before any of the VALUEFORMs are evalled.

amake
1 replies
13h47m

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

amake
0 replies
11h29m

Anyway, as far as I'm seeing it's perfectly possible to implement let* consistent with the above behavior as a macro without mutation as such:

    (define-macro (let* bindings &rest body)
      (if (null? bindings)
        `(progn ,@body)
        `(let (,(car bindings))
           (let* ,(cdr bindings)
             ,@body))))

medo-bear
0 replies
9h36m

Lisp allows you to mutate, you can certainly write non-mutating code in lisp. Why do you think you need to use mutation with let*? let* is just a sequential let

https://www.lispworks.com/documentation/lw70/CLHS/Body/s_let...

epgui
0 replies
18h24m

They don’t.

Or at least not inherently, if by “lisp” one is primarily referring to s-expressions.

tonyg
0 replies
8h41m

The first problem with this argument is that referential transparency is a property of syntactic positions, not of languages.

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.

tmvphil
0 replies
20h47m

I think SML isn't purely functional (although it naturally encourages a purely functional style).

f1shy
1 replies
21h43m

My opinion: marketing. In my experience, if I tell someone „look here is Lisp“ they turn off and roll the eyes with a „ohh that DEAD origramming language“. If I instead say „look this new state of the art language called ML“ I get full attention and respect.

ajbt200128
0 replies
21h37m

No, it's definitely not because of marketing. SML is more of a dead language than most lisps. SML is used because it has a strong type checker, which is much more conducive to learning, and just having resilient programs in general.

bmacho
1 replies
20h50m

Why would they use a Lisp dialect instead of Standard ML? It looks ugly, it looks different from math, and different concepts have the same syntax. Standard ML looks nice, it looks like math, and different concepts have different syntax.

SomeRndName11
0 replies
20h20m

No, SML is actually quite verbose ang generally ugly, compared to say OCaml or F#, or even Scheme or Closure. This is why it is dead.

vmchale
0 replies
21h42m

It is statically typed, there's a lot of depth to that side of things (Curry-Howard isomorphism)

chriswarbo
0 replies
19h9m

"Lisp" is pretty broad. Whilst it was inspired by Lambda Calculus (the core of most FP languages), a lot of Lisp code is quite imperative (loops, mutable variables, control flow separate from data flow (e.g. exceptions/errors), etc.).

Scheme (and its dialects/descendants) tend to stick to a more functional style (although they also like to do stack-gymnastics with continuations, etc.). Many courses are based around Lisp.

One of the main features of the ML family is static typing, with algebraic datatypes, pattern-matching, etc. (i.e. the stuff that new languages like to call "modern", because they first saw it in Swift or something). That gives a useful mathematical perspective on code ("denotational semantics", i.e. giving meaning to what's written; as opposed to the common "operational semantics" of what it made my laptop do), and having type checking and inference makes it easier to do generic and higher-order programming (dynamic languages make that trivial in-the-small, but can make large systems painful to implement/debug/maintain/understand). This course seems to take such abstraction seriously, since it covers modules and functors too (which are another big feature of the ML family).

NOTE: In ML, the words "functor" and "applicative functor" tend to mean something very different (generic, interface-based programming) to their use in similar languages like Haskell (mapping functions over data, and sequencing actions together)

systems
14 replies
21h57m

on 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

weatherlight
6 replies
20h42m

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.

SomeRndName11
4 replies
20h19m

The problem that is extremely verbose though. OCaml is much more concise.

weatherlight
3 replies
19h11m

Both languages encourage a concise, functional programming style but with different flavors and toolsets. They are comparable, in terms of verbosity.

I think these are correct implementations of the tower of Hanoi.

OCaml

    let rec hanoi n source target auxiliary =
      if n > 0 then begin
        hanoi (n - 1) source auxiliary target;
        Printf.printf "Move disk from %s to %s\n" source target;
        hanoi (n - 1) auxiliary target source
      end


SML

    fun hanoi n source target auxiliary =
      if n > 0 then (
        hanoi (n - 1) source auxiliary target;
        print ("Move disk from " ^ source ^ " to " ^ target ^ "\n");
        hanoi (n - 1) auxiliary target source
      )
function definition, if expressions, recursion are more concise in SML, string interpolation is nicer in OCaml

SomeRndName11
2 replies
6h31m

You SML code is incorrect, shows that you actually never coded anything in SML. SML requires that "if" always contains "else" clause (which is the norm for many functional languages). And this kind of stuff which makes SML unnecessarily verbose (OCaml has for operators, single line let definitions that do not require you to make use val and fun for different type definitions etc.).

weatherlight
1 replies
1h49m

I did Programming Languages, Part A, (to learn FP semantics) many years ago. It doesn't show I never coded anything in SML, it shows I made a mistake :/ .I no longer have Standard ML on my machine.

I thought having the `let` keyword encompass `fun` and `val.` was needlessly confusing. It's not concise. if `let` can mean so many things why not just do what Haskell did.

Again.. it not "so much more verbose." which was the initial point.

but I concede, my SML code is in fact incorrect.

SomeRndName11
0 replies
1h26m

No SML is more verbose, is pretty obvious. A simple "for" in ocaml could save lots boilerplate doing trivial recurison.

__rito__
0 replies
11h23m

Albeit little, installing SML still requires some anount of gymnastics, google searching, and copying stuff from SO, GH Gists, etc.

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.

brandonspark
6 replies
21h46m

There's a few things which go into this (hi, I'm the instructor!).

One such reason is historical. Standard ML is a research language, and a significant amount of work on it was done by professors at Carnegie Mellon, who developed the curriculum for this course.

Even setting that aside though, I fully agree with the choice to teach it in SML. For transparency, I work professionally in OCaml, so I am not unfamiliar with it, and I enjoy it quite a bit. That being said, I think that the approach taken by CMU is best summarized as the fact that languages are ephemeral, and the concepts are what matters. We don't teach programming languages, we teach concepts -- so even if SML is not widely used, the tradeoff for having students have a simpler, less distracting, and better learning experience is well worth it.

OCaml has its own intricacies that make things difficult. For instance, you can go down a lot of rabbit holes with `dune` and `utop` and `ocamlc` and `ocamlopt` and all of these things, versus SML/NJ's simple interactive REPL. Another thing is that the language is just generally more "bloated" -- you can teach modules, but then what if a student starts running into first-class modules, recursive modules, or even beyond that, GADTs and classes and objects?

(as an aside, this is my primary reason for why I would not want to teach an introductory course in Haskell. To do anything, you suddenly need to understand the concept of type classes and lazy evaluation, and that's simply too much. I don't know much about the other languages.)

I think teaching is as much enabling students to succeed as it is to prevent them from shooting themselves in the foot. For an anecdote, there is an `Option.valOf` function (of type `'a option -> 'a`), which essentially is just a bad function that should be avoided where possible. Every semester, without fail, even though we never tell students that function exists, students are smart enough to use Google, and will use it anyways, ultimately harming themselves.

I think that same mentality applies to programming language choice, here. Keep it simple, keep it neat, and make sure that the students see what is necessary for their education, and not have to spend mental energy thinking about much more.

munchler
4 replies
21h32m

As a professional who uses F# every day, I appreciate this answer, even though it concerns me. Separating concepts from practical details is worthwhile, but can be taken too far. I think the FP community probably focuses a bit too much on theory. I would encourage you to consider teaching a more practical language, like F#, in the future.

zem
2 replies
20h40m

i think someone with a good grounding in sml could get proficient ocaml or f# in under a month. sml is absolutely the right language to teach a course like this in.

munchler
1 replies
16h1m

I agree with your first sentence, but the second one surprises me. If the practical language and the impractical one are that similar, why pick the impractical one?

zem
0 replies
14h7m

sml is a smaller language, and a "cleaner" one in some ways. if your goal is to teach students the elements of functional programming, you want them to be able to concentrate on the core concepts, and not on the incidental details of the language.

http://adam.chlipala.net/mlcomp/ is a very good overview of the differences between sml and ocaml, which lets you see some of the tradeoffs each language has made.

bfors
0 replies
20h54m

I feel like F#'s commercial viability over other more computer sciencey FP languages is actually kind of a downside, from a "vibe" perspective. It seems like CS folks are not generally very interested in moving more towards the software engineering end of the discipline. Which is fair, because they are different things.

agumonkey
0 replies
16h49m

having done the proglang course by dan grossman long ago, they use sml too, i knew lisps, ocaml, and others, but sml smallness was really really appealing

frozenlettuce
12 replies
21h36m

My 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 will need to make all my functions return multiple values and later fold over all the accumulated strings and... life is too short for that. The principles really resonate with me, but maybe we are limited by the current tooling, because the development experience is quite clunky in its current stage.

tromp
1 replies
21h18m

Sometimes I just want to do something silly, like adding a log somewhere.

In Haskell, you can use Debug.Trace for just that purpose, when you don't want to change the type of your function.

frozenlettuce
0 replies
20h56m

I've been playing with purescript and found out that they have a similar library, thanks!

mrkeen
1 replies
21h27m

Just let all your functions live in IO then. You'll still come out ahead.

Or do an unsafePerformIO.

Or use trace (where someone else has done the unsafePerformIO for you).

Or use a Writer.

Or introduce some logging capability (Logger m =>) onto your code.

Or take a look at all the man-hours that have been spent on trying to perfect logging: https://hackage.haskell.org/packages/tag/logging

frozenlettuce
0 replies
20h57m

yeah, biting the bullet seems to be the way to go. As you mention the lots of "man-hours that have been spent on trying to perfect logging", when doing research the usage of that time might be ok, but when building a product you might need to make concessions.

brandonspark
1 replies
21h32m

This is Haskell-specific, it sounds like. I agree, the IO monad is really quite inconvenient sometimes.

I work in OCaml, which is also a functional language, but prints can be added in single lines. I address this point in Lecture 19 (Imperative Programming), actually, but my perspective is -- we invented immutability and purity to serve us, but we need not be fanatically beholden to it. In my opinion, I think Haskell goes in that direction, when every usage of IO now needs the IO monad to get involved.

A little mutability is OK. Functional programming is about the avoidance of side effects, more than simply forbidding it.

frozenlettuce
0 replies
21h9m

yeah, I've been trying to get this mindset as well - even though sometimes I feel that I'm "cheating" :)

ElectricalUnion
1 replies
21h6m

From my limited knowledge of FP languages it is expected that pure code in fact doesn't evaluate anything until a monad forces it to evaluate.

You would then need a monad to evaluate the things you're attempting to log. And at that point you have a monad, so you can log as usual?

squillion
0 replies
19h40m

It's not about monads, it's about effectful code, which is represented by special types (e.g. IO in Haskell, Eff in PureScript). Effectful code can call pure code, but not vice-versa. Since a program will have to do something, the main function is always effectful, i.e. it returns an effectful special type. So you're right that pure code isn't evaluated until some effectful code is ultimately returned by the main function and executed (by a runtime or equivalent). However, in purely functional languages most code is pure, even though it's ultimately called by effectful code.

Monads and side-effects aren't intrinsically related. Simplifying, a monad is something with flatMap() - in JavaScript, Array and Promise are monads (kinda). What flatMap() gives you is the ability to chain things, which is useful to sequence side-effects so that they can be performed by a machine in a given order. That's why IO and Eff are monads.

zogrodea
0 replies
9h3m

Others have mentioned having the same problem with this issue. One post I particularly like about the subject is this one on function colouring (how lagnuages with async/await syntax have a similar "infection"; this is a response to the original post on function colouring and not the original post). https://www.tedinski.com/2018/11/13/function-coloring.html

toast0
0 replies
21h6m

You might benefit from a more pragmatic functional language. Erlang is broadly functional, but you can output from anywhere if you want to. It's probably one of the least pure functional languages out there, but it's super handy.

poorlyknit
0 replies
19h20m

In Haskell you have a lot of options to type your functions in a more granular way. Consider the type class MonadIO, which lets you specify that your function works on any monad that can do side effects, not just IO specifically:

    -- Before
    captureAudioDuration :: DeviceID -> DiffTime -> IO WaveData
    -- After
    captureAudioDuration' :: MonadIO m => DeviceID -> DiffTime -> m WaveData
You can build the same thing, but for logging!

    class Monad m => MonadLog m where
        log :: String -> m ()
    -- In IO, just log to stdout.
    -- Other implementations might be a state/writer monad
    -- or a library/application-specific monad for business logic.
    instance MonadLog IO where
        log msg = putStrLn ("log: " ++ msg)
    -- Before: Bad, doesn't actually do any IO but logging
    findShortestPath :: Node -> Node -> Graph -> IO [Node]
    -- After: Better, type signature gives us more details on what's happening.
    -- We can still use this in an IO context because IO has a MonadLog instance.
    -- However, trying to capture audio in this function using either
    -- of the functions above will lead to a type error.
    findShortestPath' :: MonadLog m => Node -> Node -> Graph -> m [Node]
As you can imagine this can get quite verbose and there's other patterns one can use. Feel free to ask any follow-up questions :)

corethree
0 replies
11h23m

If I choose to add said side effect, now all my functions are marked with an io signature

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.

frankbreetz
9 replies
22h5m

Does this include exercises? I didn't see any and I always find that the most useful part of learning.

brandonspark
4 replies
21h41m

Unfortunately, it does not. These lectures are "mine", in the sense that I developed all of them myself, but the homeworks and lab exercises are the combined efforts of generations of TAs and instructors from the past. It wouldn't be right for me to give them away. (they are also reused from time to time, so there are academic integrity concerns with that also)

brandonspark
2 replies
21h39m

(but I have thought of developing my own exercises independently to go with the lectures, to post on my website. This is generally a lot of work, though, so this might take some time, depending on how much people would benefit from it.)

bombcar
1 replies
15h0m

Could be a classic kickstarter campaign style thing.

brandonspark
0 replies
14h8m

Haha, maybe. I'm not looking to earn any money from this, though. Time is the bigger constraint in my life at the moment.

doktrin
0 replies
8h19m

TIL. Given that 15-213 has been widely available for years I naively assumed this would also hold true for other undergrad CS courses, but apparently not.

mbivert
0 replies
21h3m

Rewriting standard list functions (map, fold, sum, etc.) is a good entry-level exercise.

A λ-calculus interpreter can be used as an intermediate level exercise. It is in particularly valuable in the context of solidifying one's understanding of functional programming.

You can also use "standard" textbooks, such as the SICP [0], and perform the exercises using the language of your choice, instead of Scheme/LISP.

[0]: https://mitp-content-server.mit.edu/books/content/sectbyfn/b...

fredgrott
0 replies
21h42m

making up your exercises is part of that fun journey of creating your own toolbox of functional programming in your language of choice!

brandonspark
0 replies
20h52m

If you get to around lecture 9, a classic example I always tell people to start with is a calculator!

For instance, here's the SML code for it:

``` datatype exp =

    Num of int

  | Plus of exp * exp

  | Minus of exp * exp

  | Times of exp * exp

  | Div of exp * exp

```

Implement the function `eval : exp -> int`, which evaluates the expression as best as it can. Assume no division by zero.

Extra credit: Can you implement `eval' : exp -> int option`, that returns `SOME n` if the expression evaluates, and `NONE` if it divides by zero?

PennRobotics
0 replies
21h42m

Not exactly exercises, but there's https://smlhelp.github.io/book/docs/ which supports the course and explains each of the concepts as well as library documentation at the official class site, http://www.cs.cmu.edu/~15150/resources.html

It looks like their current workflow keeps exams and homeworks off the internet effectively, but there's a 6-year-old codebase at https://github.com/zhengguan/15150-1 with 10-year-old homeworks and such.

c-c-c-c-c
7 replies
22h4m

Wow, he went from taking his bachelor to lecturing.

I always dreamt of that when going through my degree and encountering courses that needed a thorough rework.

shortrounddev2
6 replies
21h41m

tbh if I were in a class taught by someone who had JUST finished their bachelor's degree, I'd take a lot of it with a grain of salt

medstrom
3 replies
21h23m

If you expect perfect factual accuracy from your teachers, yeah. On the flip side, they don't have the curse of knowledge yet i.e. it's still fresh in their mind what was difficult in the beginning, so they can probably explain very well. Just keep in mind who's teaching you, and it's just like if a co-student teaches you.

And if you feel you have to take what you hear with a grain of salt, that's probably good for your learning too.

shortrounddev2
2 replies
21h9m

I just mean in terms of experience. If you deviate from textbook accuracy and go into providing practical advice for real-life scenarios, someone with only a bachelor's and no work history is someone who can only give you canned anecdotes from others. Looking at his resume, it looks like he's had some internships so he has a bit of experience, and that's probably worth something

gtchuang
1 replies
19h22m

His main day job is as a SWE doing program analysis, so I'm pretty sure he's got the credentials to talk about real-life scenarios.

shortrounddev2
0 replies
19h9m

Yeah idk anything about the guy

elchananHaas
1 replies
21h18m

I went to CMU and was in AEPI fraternity with Brandon Wu. Brandon Wu is exceptional when it comes to functional programming. He was head TA of 15150 for a year, I have 100% confidence in him.

He took a break from TAing for some time, and when he returned he decided to have some fun with his application. He wrote a transpiler from a C like syntax to SML the day before his interview, and used it to joke that they should transition to teaching functional programming in C.

shortrounddev2
0 replies
21h11m

Yeah idk anything about him in particular. I just mean that, on paper, someone who goes straight from bachelor's to teaching is someone who doesn't really have any experience. I notice that a lot of the people who extol the virtues of FP to me are a lot of people straight out of college and have little real-world reference for why FP is useful in a prod environment

imslavko
6 replies
21h31m

Slightly off-topic but what's a good forum to seek help on FP practices outside of the courses like this online?

Every winter break I get back into trying to learn more FP (in Haskell) and in the past several years I have been practicing algo problems (codeforces, advent of code, leetcode).

I always get stuck on more advanced graph algorithms where you traverse a and modify a graph, not a tree structure - it gets particularly tricky to work on circular data structures (I learned about "tying the knot" but it's incredibly challenging for me) and usually the runtime perf is sub-par both asymptotically and empirically.

kccqzy
4 replies
20h40m

Many graph algorithms are designed for imperative programming. It's safe to say that functional graph programming is still in its infancy. Alga[0], a system for algebraic graphs only came out in 2017. And efficient algorithms for graphs may yet to be discovered (even something as simple as reversing a list that's both efficient and elegant only came out in 1986!)

That said, as a beginner in functional programming, it would probably be good enough if you just focus on directly translating imperative graph algorithms to functional programming. You simply solve the problem by programming at a slightly lower level of abstraction.

[0]: https://dl.acm.org/authorize?N46678 or preprint at https://github.com/snowleopard/alga-paper/releases/download/...

philsnow
3 replies
20h0m

I don't know if [0] would be any help, it doesn't talk about graphs in particular but does talk about functional-focused approaches to data structures. This note[1] on the wikipedia page for the book says it better than I could:

[...] consider a function that accepts a mutable list, removes the first element from the list, and returns that element. In a purely functional setting, removing an element from the list produces a new and shorter list, but does not update the original one. In order to be useful, therefore, a purely functional version of this function is likely to have to return the new list along with the removed element. In the most general case, a program converted in this way must return the "state" or "store" of the program as an additional result from every function call. Such a program is said to be written in store-passing style.

[0] https://www.cs.cmu.edu/~rwh/students/okasaki.pdf

[1] https://en.wikipedia.org/wiki/Purely_functional_data_structu...

imslavko
2 replies
18h4m

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 you say "screw it, this abstracted function does some stateful temporary business, but it looks pure from the outside" but in Haskell it's a lot harder to pull off without going deep into monads (and I forget how those work every time).

kccqzy
1 replies
16h3m

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.

imslavko
0 replies
12h3m

I don't think I have heard of the automatic AoS/AoS before, do you have good links to study more?

low_tech_punk
0 replies
21h0m

My Scala friends heavily rely on discord, e.g. the one mentioned here: https://typelevel.org/blog/2021/05/05/discord-migration.html

It is language based community but they do have vibrant discussion on learning and theories.

freedomben
4 replies
22h15m

I do wish functional programming were more taught. we're getting to a point where I almost think OOP should be taught briefly and the rest of the focus on C/C++ for low level stuff (OS, data structures, some algorithms), and something functional or pseudo-functional for high level stuff. Most of the newer codebases in startups now require functional concepts to understand what's happening. For example, try writing modern JS without understanding .map, .reduce, et al, and function passing, etc.

Regardless I think it's important that students get exposed to more than just Python, which seems to increasingly be the only thing students come out knowing.

Mandelmus
3 replies
22h5m

I do wish functional programming were more taught

My first CS bachelor's semester in Germany in 2017 taught functional programming using Haskell (as well as C and NASM assembly in another course on computer architecture).

OOP using Java and Python was only introduced in the second semester.

Regardless I think it's important that students get exposed to more than just Python, which seems to increasingly be the only thing students come out knowing.

In my B.Sc. studies I used C, C++, Haskel, Assembly, Java, Python, and Swift.

randmeerkat
0 replies
21h57m

My first CS bachelor's semester in Germany in 2017 taught functional programming using Haskell (as well as C and NASM assembly in another course on computer architecture).

Also worth mentioning that since this was in Germany not only was it a great education, but there’s no crippling student debt either.

freedomben
0 replies
22h0m

There are definitely some good schools out there that expose students to a broad field. For anybody who is a student and looking, this is somethign I would strongly recommend considering.

RamblingCTO
0 replies
21h55m

Same here. Had Scala in my first year. Clojure and Racket later. On top of that I had C, ASM, Java, Python and R (had a focus on machine learning). So I got plenty of education in that department.

aroman
4 replies
21h7m

150 was one of my favorite courses at CMU; each homework really made me feel like I unlocked a new level of reasoning with code.

louthy
1 replies
20h8m

That's how I felt when I discovered FP after more than two decades writing procedural and OO code. It felt like I'd found a secret room where all the reasoning was kept.

adamddev1
0 replies
12h9m

Yes! I love this description!

3abiton
1 replies
19h8m

Do you if any of the course material is available online or as a MOOC?

rashkov
0 replies
15h21m

Have a look at this similar course: https://www.coursera.org/learn/programming-languages I enjoyed it quite a bit and the lecturer is fantastic. It also uses SML and teaches similar material, though maybe not as in depth since this is just the first section of a three-part semester long course.

Koshkin
4 replies
20h51m

It seems that the fundamental problem with the functional paradigm (in its pure form) is that the real world - including the architecture of the computer that is used to run the programs on - is full of side effects, i.e. is essentially "imperative," and with this impedance between them the idea creates more problems than it solves.

whateveracct
1 replies
20h47m

on the contrary, i think FP (Haskell at least) gives you more & better tools to represent and wrangle side effects

kccqzy
0 replies
20h34m

Exactly. These languages come up with more and more strategies and abstractions (from monads to modern effect systems) to help you manage your side effects well. It then raises the level of abstraction in your programs to become simpler and more concise.

epgui
1 replies
18h10m

That’s like saying the problem with rulers is that the real world doesn’t have straight lines.

Or the problem with cleaning your room is that in the real world entropy only ever increases.

kccqzy
0 replies
17h4m

Any time an HN comment uses the phrase "fundamental problem" chances are the problem is not only not fundamental, but also rather fun to solve for the right kind of people.

narinxas
3 replies
22h3m

just in time for nobody to really care about programming because LLMs are so good at translation and all computer code and programing are a subfield of linguistics...

shepherdjerred
0 replies
21h19m

Functional programming is a perfect pairing with AI-generated code because the type systems are generally more expressive than non-functional languages, which means the compilers can catch all sorts of errors.

interiorchurch
0 replies
21h53m

As my mother used to say, we'll see...

Verdex
0 replies
21h28m

Programming runs along the back of mathematics. A field famous for spending centuries wasting time on silly games until those same silly games end up being the foundation on which modern society functions.

Even if LLMs completely remove the need for programming (a rather big IF), this is not time wasted.

jstrieb
2 replies
17h44m

I loved 150 when I took it, and program in SML from time to time to this day.

Bob Harper (a CMU professor with a focus on PL theory) also has a really good SML reference that is closer to a textbook than lecture notes.

http://www.cs.cmu.edu/~rwh/isml/book.pdf

zelphirkalt
1 replies
4h12m

I found the regular expression package as a first thing to make in SML waaay too complex. You already need to have a good understanding of the elements of SML syntax to understand how it works. This is definitely not for SML beginners. I recommend "Elements of ML Programming" by Jeffrey D. Ullman for people starting to learn SML. It too has some corners, that are less great for not so mathematically inclined people, but you will definitely learn the language and have exercises.

jstrieb
0 replies
1h51m

This is valid criticism, and I agree. The regular expression example is not made easier by his use of non-standard regex syntax.

I have not read Dr. Harper's book cover to cover; I treat it as a reference. For that, it is quite useful.

The same criticism of his SML book could also be made of his Practical Foundations for Programming Languages book. It's a massive, dense tome that is probably great for other professors to use as the basis for a course, but (in my opinion) serves as a mediocre introduction if you have never seen the material before.

https://www.cs.cmu.edu/~rwh/pfpl.html

vermilingua
1 replies
20h10m

Content aside, what gorgeous slides. I wish any of my lecturers had the same eye for presentation.

PennRobotics
0 replies
7h57m

Partial template source of the slides is available at https://github.com/jacobneu/150lectureNotes (For the uninitiated, it's a Beamer theme, compiled with LaTeX)

Some assembly required; use the instructions from https://github.com/jacobneu/alleycat as inspiration, use the scripts (e.g. startLecture) and Makefile in /crucible

low_tech_punk
1 replies
21h3m

God send!! The FP learning resource is quite sparse on the internet. I’ve been looking for structured material like this for a while.

adamddev1
0 replies
12h7m

If you're fairly new to FP I really recommend working through https://htdp.org.

zubairq
0 replies
21h23m

Watching it now

valenterry
0 replies
9h18m

No word on where the concept originally comes from? (in the text/description)

Should have at least differentiated between "functional programming" and "pure functional programming" IMHO.

hohohmm
0 replies
15h13m

Use to be called 15-212. TA-ed it for 1 semester. That's when I really understood programming.

gsuuon
0 replies
18h19m

This looks cool! Just a note, it looks like the youtube playlist is in reverse order: https://www.youtube.com/watch?v=DSGXB9G5dxk&list=PLsydD1kw8j...

esafak
0 replies
17h35m

Pretty good for a new grad!

asicsp
0 replies
12h42m
andrewl
0 replies
22h10m

This looks valuable. And it is from the summer of 2023, so quite current.

ajbt200128
0 replies
22h8m

Of note, CMU produces a bunch of functional programming research, including a whole homotopy type theory department, so this is a quality source.

airstrike
0 replies
20h50m

Hey Brandon, thanks for posting this. Off-topic but maybe consider serving up thumbnails on that page instead of the full-size pngs https://brandonspark.github.io/prologue/lecture01.png

PennRobotics
0 replies
22h14m

Standard ML (sml / smlnj)

The instructor is clear, energetic, has a decent flow in the first lecture e.g. emphasizes the important points with vigor and repetition, switches media every 10 or 15 minutes, has a conversation with students. Slides are relatively noise-free and are informative; terms to know are highlighted.

I haven't watched a full functional programming lecture series yet, but I'd gladly audit this one.

As a "new" instructor (as in, not a TA anymore) he's got a bit of teaching talent. I hope he keeps a tight feedback loop and improves every year and continues publishing material.