A question about computer programming: What's wrong with mutable variables?

I not disagreeing with you at all. My point is that on
Chessboard() you have 64 mostly independent variables. It’s much more efficient to represent the game move and mutating 2 of those variables, rather than creating a new state that is a copy of 62 and a new version of 2.

((And Yeah for the Chess pedants out there I’m ignoring castling where more than two change)
(And for the programming pedants out there I’m ignoring the possible compressions where you don’t create a state for empty squares at all, so 64 isn’t necessary)
The point still stands that mutating drops overhead significantly over a stubborn insistence on immutability)

nvm wrong context

Actually… well, Haskell’s definition of filter just uses list comprehension.

filter :: (a -> Bool) -> [a] -> [a]
filter p xs = [ x | x <- xs, p x]

This literally reads “filter takes a function p, and a list xs. It returns a list that contains all elements, x, such that x is in xs and p(x) is true”.

That’s as far down the rabbit hole the code goes. I assume Scala is similar.

And then how is length defined?

I can’t find explicit, source, but the docs mention it’s O(n), so it’s probably not magic. You could trivially implement it like this:



length :: [a] -> Int
length (_:xs) = length(xs)+1
length [] = 0


This means “length takes a list of stuff, and returns an integer.” "If the list is not empty, split the list into two parts: the first element (which we ignore) and a list containing everything after the first element, we’ll call this “xs”. Recursively call this function with this list called “xs”. Add one to this result.

If the list is empty, return 0."

How about I walk you though a method to count all of the prime numbers in a list, but without using any of the higher order functions, but using recursion. That might be instructive.

(First, note that the bit of code “1 to n” in Scala is just shorthand for “1.to(n)” where “to” is a method on the Int class that constructs a list of all the ints from 1 to n, so for now, take it for granted that we can construct a list from 1 to n easily).

We can write a function that counts all of the primes in a list as


def countPrimes(xs:List[Int]) = {
  if (xs.isEmpty) 0
  else if (isPrime(xs.head)) 1 + countPrimes(xs.tail)
  else countPrimes(xs.tail)
}

To break this down, the function looks at the list and determines three cases:

[ul]
[li]If the list is empty, clearly there are no primes in it.[/li][li]If the list is non-empty and first element of the list is prime, the number of primes in the list is one greater than the number or primes in the tail of the list.[/li][li]If the list is non-empty and first element of the list is *not *prime, the number of primes in the list is just the number or primes in the tail of the list.[/li][/ul]

which are all manifestly true statements.

Note that this function does not have any vars and is entirely referentially transparent. If we want a function that counts primes up to a certain n, we can just put:


def countPrimes(n:Int) = countPrimes((1 to n).toList)

You could also write the function in another way that makes it a bit clearer where the accumulator is going, by using a second parameter in the function to indicate “number of primes we’ve seen already” to get:


def countPrimes(xs:List[Int], numWeveSeen:Int) = {
  if (xs.isEmpty) numWeveSeen
  else if (isPrime(xs.head)) countPrimes(xs.tail, numWeveSeen + 1)
  else countPrimes(xs.tail, numWeveSeen)
}

def countPrimes(n:Int) = countPrimes((1 to n).toList, 0)


In this the cases change slightly:

[ul]
[li]If the list is empty, clearly there are no primes in it, so the number of primes is the number we have seen already.[/li][li]If the list is non-empty and first element of the list is prime, the number of primes in the list is the number or primes in the tail of the list, plus the number we have seen already, plus one.[/li][li]If the list is non-empty and first element of the list is *not *prime, the number of primes in the list is just the number or primes in the tail of the list, plus the number we have seen already.[/li][/ul]

I include this way of writing it because it makes it obvious that the accumulator has been replaced with a parameter that gets passed through the call stack, but still no vars.

@Jragon’s post:

I’m going to read it a few more times to make sure, but I think this explains everything. Thank you for that!

I’m a philosophy teacher. Someone once said about philosophy types that they “worry that what works in practice won’t work in theory.” I think you may have just assuaged my theoretical worries. :wink:

@leahim’s post:

Ditto what I just said.

Thank you guys for sticking with me on this.

Don’t worry. Functional programmers just worry that what works in practice may not be hard enough to work in theory.

Just so Frylock has some Scala, something equivalent would be:


def filter(xs:List[A], f:A=>Boolean):List[A] = {
  if (xs == Nil) Nil
  else if (f(xs.head)) xs.head :: filter(xs.tail, f)
  else filter(xs.tail, f)
}

and length would be


def length(xs:List[A]):Int = {
  if (xs == Nil) 0
  else 1 + length(xs.tail)
}

(Although the real Scala implementations are probably a lot more complicated and higher up in GenTraversableOnceLike or something like that :slight_smile: .)

In theory, theory and practice are identical, but in practice they are not.

leachim –

Out of wonder, does Scala have the same conceit as Haskell – that all functions only take a single argument (or no arguments)?

Because in Haskell, while I didn’t want to say it earlier,

filter prime [1…n]

Is technically two steps:

  1. evaluate “filter prime” which returns an anonymous function of the type “[a] -> [a]”
  2. Call this anonymous function on the list [1…n]

It looks like Scala just flat out uses multiple arguments instead of having the “all functions are uniform, multiple arguments are just tuples or currying”, is that the case or is the syntax sneaky?

Well, and the Haskell list comprehension implementation is obviously more complex and implemented in the compiler ;).

No, Scala is a real programming language ( :smiley: ) and can have functions of more than one variable.

Yeah, Scala is not as in love with Currying as the language named after Curry is. :slight_smile:

It does have a “multiple parameter list” syntax for defining functions like:


def f(a:Type1, b:Type2)(c:Type3, d:Type4):ReturnType = ...

which is syntactic sugar for something like:


def f(a:Type1, b:Type2):(c:Type3, d:Type4) => ReturnType = ...

Which kind of helps with a bit of Currying for some pre-specified arrangements.

Most of this is due to the fact that this runs on the JVM and the JVM specifies how calls are made.

Join us next week when we explain Prolog followed by a deep sense of general malaise and ennui!

When you’re done with Prolog, how about Perl or regular expressions?

Frankly this was useful to me. I used to teach a course in F# (don’t laugh), but the “count one more” quote explains a lot.

I only know regular expressions in the sense that I’m fairly good at proving things about finite state automata. These Ruby/Perl style regular expressions may as well be magic to me.

The only reason Prolog makes me cry is because it pretends it’s first order logic like a jerk and then makes you actually care about the order of your predicates. Literally 90% of all Prolog bugs I’ve ever had have been infinite recursion because I put one predicate before another.