Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> There were four 15-unit courses, each about one of these "languages":

The description you offer is strange to me. The Lisp family of languages are multi-paradigm (arguably paradigm-independent) and can hardly be called "procedural". The core material of SICP revolves around considering the "means of combination" and "means of abstraction" offered by a programming language — concepts that sound to me like they have far more to do with "structure", "architecture" and "functionality" than with "procedure".



You're absolutely right that "procedural", at least as I understand the word in 2025, is a poor label for 6.001.

6.001 taught 'define' and 'let' but didn't teach 'set!' until week 6 or so. So we learned functions, variables, scopes, recursion, lambdas, strings, numbers, symbols, lists, map, filter, flatten, and more - all without ever modifying a variable. That's very "functional".

Once we learned that it was possible modify existing variables, we learned object-oriented programming; objects were just lambdas with closures that took messages indicating which function to call. We then learned a fake assembly language written in scheme that had both an interpreter and a compiler, also written in scheme. While "procedural" feels wrong, I'm not sure what label one could apply to all this...


Given their definition of procedural, the term makes sense. The book is about processes and procedures that describe how they're executed or things are computed, versus describing what is computed (mathematical sense, declarative or more declarative, closer to some popular meanings of functional programming today).

They define functional programming as "[p]rogramming without any use of assignments". Which would be a subset of procedural programming in the sense that they mean it.

They also contrast imperative and functional programming (the first being with assignments and mutations, the latter without). Both imperative and functional programming can reasonably fall under procedural programming using their definitions.


The fuller excerpt concretely put in §3.1.3 "The Costs of Introducing Assignment":

"So long as we do not use assignments, two evaluations of the same procedure with the same arguments will produce the same result, so that procedures can be viewed as computing mathematical functions. Programming without any use of assignments, as we did throughout the first two chapters of this book, is accordingly known as functional programming."


Btw, I've just read the first section of Chapter 5 [Computing with Register Machines] for the first time, and think it's the best introduction to assembly that I've seen (and I've seen a few).

Calling it 'fake' is dismissive. Also, it isn't written in Scheme, but merely described in the native data format: lists of symbols.

The next section builds a virtual machine that is written in Scheme to run the code. One of the beauties of Scheme/Lisp (and source of much of its power) is the simplicity of the syntax. It allows it to be incredibly succinct.

The last section in the chapter builds a compiler to translate Scheme into this virtual machine assembly code so you can run it in the virtual machine simulator. An ouroboros.

SICP is a gem. Thank you Hal and Gerry!


I can see how 6.001 was a bit like jumping into the deep end to learn to swim.

Starting from, "To design a register machine, we must design its data paths (registers and operations) and the controller that sequences these operations." In less than 5,000 words it proceeds to implementing recursive procedure calls in what amounts to assembly:

  (controller
    (assign continue (label fact-done))   ; set up final return address 
   fact-loop
    (test (op =) (reg n) (const 1))
    (branch (label base-case))
    (save continue)                       ; Set up for the recursive call
    (save n)                              ; by saving n and continue.
    (assign n (op -) (reg n) (const 1))   ; Set up continue so that the
    (assign continue (label after-fact))  ; computation will continue
    (goto (label fact-loop))              ; at after-fact when the
   after-fact                             ; subroutine returns.
    (restore n)
    (restore continue)
    (assign val (op *) (reg n) (reg val)) ; val now contains n(n - 1)!
    (goto (reg continue))                 ; return to caller
   base-case
    (assign val (const 1))                ; base case: 1! = 1
    (goto (reg continue))                 ; return to caller 
   fact-done)
A translation of:

  (define (factorial n)
    (if (= n 1) 
        1
        (* (factorial (- n 1)) n)))
It's quite a jump in knowledge, but explained very clearly through a series of guided examples. It's close to equivalent code in x86 or arm, but much easier to read.


"Programming Should Eat Itself" by Nada Amin https://www.youtube.com/watch?v=SrKj4hYic5A

The future of AI code generation?

https://neurosymbolic.metareflection.club/


Strange Loop Language Panel - Hickey, Sussman, Wirfs-Brock, Pamer, Alexandrescu, Ashkenas (2011)

https://youtu.be/zhZMaF8vq5Y?t=297

Sussman:

well it's really very hard to find the worst idea because there are so many bad ideas in programming languages. of course the ones that bother me the most are the ones that are designed to keep me from doing what i want. i was after all a libertarian programmer. okay. and so i don't want anybody to tread on me, but the worst features of languages that i can think of -- the really worst thing -- is complex syntax. okay. and as alan perlis quipped, syntactic sugar yields cancer of the semicolon. okay. the problem with complex syntax is that it hides possibly important to understand mechanisms, but more importantly it makes it very difficult to write programs that manipulate programs -- that read them, that write them and analyze them. and that, in fact, i often have programs that write programs that i want to run in-line. for example, numerical programs that are constructed from symbolic algebra expressions. okay. so that's a nice feature of lisp, for example, which has lots of parentheses, is a uniform representation of programs as data and the ability to execute code that you've just constructed. and as a consequence i would say my mantra here is syntax without representation is tyranny.


It's very "functional" in the "functional programming" sense, but not at all in the sense that 6.003 is about the "functional" descriptions of LTI systems (i.e., that the "signal" output of a "system" is a function of the input, which you can do things like take the Laplace transform of). "Procedural" is the term used in the class's textbook, and the "functions" in Scheme are called "procedures" in the Scheme standard.


Wizardry!


I'm a bit disappointed by some of the responses you received and that you were apparently downvoted.

Here's some text from Chapter 1 of the book that might make this clearer:

> Procedures, as introduced above, are much like ordinary mathematical functions. They specify a value that is determined by one or more parameters. But there is an important difference between mathematical functions and computer procedures. Procedures must be effective.

> As a case in point, consider the problem of computing square roots. We can define the square-root function as √x = the y such that y≥0 and y^2 = x .

> This describes a perfectly legitimate mathematical function. We could use it to recognize whether one number is the square root of another, or to derive facts about square roots in general. On the other hand, the definition does not describe a procedure. Indeed, it tells us almost nothing about how to actually find the square root of a given number. It will not help matters to rephrase this definition in pseudo-Lisp:

    (define (sqrt x)
      (the y (and (>= y 0)
        (= (square y) x))))
> This only begs the question.

> The contrast between function and procedure is a reflection of the general distinction between describing properties of things and describing how to do things, or, as it is sometimes referred to, the distinction between declarative knowledge and imperative knowledge. In mathematics we are usually concerned with declarative (what is) descriptions, whereas in computer science we are usually concerned with imperative (how to) descriptions.

[There's more after this, but it is off-topic for our purposes.] IMHO you're not wrong and you shouldn't've been downvoted. I think there's just an issue with semantic drift and evolving terminology and map-is-not-the-territory and so forth going on.


I appreciate it. The observation was really intended to be about the semantic drift, and the odd coincidence of language.


SICP is fundamentally about the notion that programs are primarily a means of communication between people, being written by people for other people to read, and only secondarily a thing for computers to execute. And it really opened my eyes to the landscape of programming paradigms that exist—indeed, it continues to do so!

But your comment is completely off-base.

In Circuits and Electronics, as I understand it, the "structures" being discussed are circuit schematics, things like this keyboard I designed last month https://tinyurl.com/23tdsm4c. While SICP does talk about circuit schematics, I don't think anyone would claim that S-expressions are a reasonable alternative way for people to read and write such things.

You're completely confused about Signals and Systems, because you said "functionality", a word which refers to the kind of "functional" a machine might be. In that context, saying that something is "functional" means that it works. But the "functional" that describes Signals and Systems is the mathematical idea of a "function", which is a not-necessarily-computable relation of each possible input to one (possibly not distinct) output. The kinds of "functions" we're talking in S&S are the kinds of functions where you can take the Laplace transform or plot the frequency and phase response. It isn't about functionality at all!

While S-expressions are perfectly capable of expressing ideas like these, and indeed SICM investigates those possibilities in much more detail, SICM hadn't been written yet, and SICP and 6.001 touch on them only briefly. Following SICM I think even its authors were doubtful about whether Scheme was a good medium for working with those ideas.

I don't know anything about Computation Structures, so I can't really say anything about it. Maybe you're right that it would fit perfectly well into 6.001. Apparently it survived the purge; https://ocw.mit.edu/courses/6-004-computation-structures-spr... says:

> This course introduces architecture of digital systems, emphasizing structural principles common to a wide range of technologies. It covers the topics including multilevel implementation strategies, definition of new primitives (e.g., gates, instructions, procedures, processes) and their mechanization using lower-level elements. It also includes analysis of potential concurrency, precedence constraints and performance measures, pipelined and multidimensional systems, instruction set design issues and architectural support for contemporary software structures.


> Following SICM I think even its authors were doubtful about whether Scheme was a good medium for working with those ideas.

Hrm https://mitp-content-server.mit.edu/books/content/sectbyfn/b...


This looks awesome! Maybe they were joking.


> SICP is fundamentally about the notion that programs are primarily a means of communication between people, being written by people for other people to read, and only secondarily a thing for computers to execute.

Kragen, I think you hit the nail on the head with this.

From the 1e Preface:

"Our design of this introductory computer-science subject reflects two major concerns. First, we want to establish the idea that a computer language is not just a way of getting a computer to perform operations but rather that it is a novel formal medium for expressing ideas about methodology. Thus, programs must be written for people to read, and only incidentally for machines to execute."

And also,

"Second, we believe that the essential material to be addressed by a subject at this level is not the syntax of particular programming-language constructs, nor clever algorithms for computing particular functions efficiently, nor even the mathematical analysis of algorithms and the foundations of computing, but rather the techniques used to control the intellectual complexity of large software systems."

6.001 germinated in 1978! There were far fewer languages to choose from then.[0] As elegant, and expressive, and powerful as Scheme is (being an attempt to strip a language down to the essentials), perhaps there just are more legible languages these days. A good exercise would be to go to Rosetta Code[1], pick a program, and compare the aesthetics of the code. What solutions are the cleanest and easiest to understand?

[0]: https://en.wikipedia.org/wiki/Timeline_of_programming_langua...

[1]: https://rosettacode.org/wiki/FizzBuzz#


Some notable examples:

(pulled from https://rosettacode.org/)

  --------------------------------
  [[ Scheme ]]
  
  (do ((i 1 (+ i 1)))
      ((> i 100))
      (display
        (cond ((= 0 (modulo i 15)) "FizzBuzz")
              ((= 0 (modulo i 3))  "Fizz")
              ((= 0 (modulo i 5))  "Buzz")
              (else                 i)))
      (newline))
  
  --------------------------------
  [[ Python ]]
  
  for i in range(1, 101):
      if i % 15 == 0:
          print("FizzBuzz")
      elif i % 3 == 0:
          print("Fizz")
      elif i % 5 == 0:
          print("Buzz")
      else:
          print(i)
  
  --------------------------------
  [[ Logo ]]
  
  to fizzbuzz :n
    output cond [ [[equal? 0 modulo :n 15] "FizzBuzz]
                  [[equal? 0 modulo :n  5] "Buzz]
                  [[equal? 0 modulo :n  3] "Fizz]
                  [else :n] ]
  end
  
  repeat 100 [print fizzbuzz #]
  
  --------------------------------
  [[ Racket ]]
  
  (for ([n (in-range 1 101)]) 
    (displayln 
      (match (gcd n 15) 
        [15 "fizzbuzz"] 
        [ 3 "fizz"] 
        [ 5 "buzz"] 
        [ _  n])))
  
  --------------------------------
  [[ Arc ]]
  
  (for n 1 100 
       (prn:check (string (when (multiple n 3) 'Fizz) 
                          (when (multiple n 5) 'Buzz)) 
                  ~empty n)) ; check created string not empty, else return n

  --------------------------------
  [[ Rust ]]
  
  fn main() {
      for i in 1..=100 {
          match (i % 3, i % 5) {
              (0, 0) => println!("fizzbuzz"),
              (0, _) => println!("fizz"),
              (_, 0) => println!("buzz"),
              (_, _) => println!("{}", i),
          }
      }
  }
  
  --------------------------------
  [[ Julia ]]
  
  for i in 1:100
      if i % 15 == 0
          println("FizzBuzz")
      elseif i % 3 == 0
          println("Fizz")
      elseif i % 5 == 0
          println("Buzz")
      else
          println(i)
      end
  end
  
  --------------------------------
  [[ Hy ]]
  
  (for [i (range 1 101)] (print (cond
    [(not (% i 15)) "FizzBuzz"]
    [(not (% i  5)) "Buzz"]
    [(not (% i  3)) "Fizz"]
    [True            i])))

  --------------------------------
  [[ Crystal ]]
  
  1.upto(100) do |v|
    p fizz_buzz(v)
  end

  def fizz_buzz(value)
    word = ""
    word += "fizz" if value % 3 == 0
    word += "buzz" if value % 5 == 0
    word += value.to_s if word.empty?
    word
  end
  
  --------------------------------
  [[ Perl ]]
  
  for my $i (1..100) {
      say $i % 15 == 0 ? "FizzBuzz"
        : $i %  3 == 0 ? "Fizz"
        : $i %  5 == 0 ? "Buzz"
        : $i;
  }
  
  --------------------------------
  [[ Ruby ]]
  
  1.upto(100) do |n|
    print "Fizz" if a = (n % 3).zero?
    print "Buzz" if b = (n % 5).zero?
    print n unless (a || b)
    puts
  end
  
  --------------------------------
  [[ Prolog ]]
  
  fizzbuzz(X) :- X mod 15 =:= 0, !, write('FizzBuzz').
  fizzbuzz(X) :- X mod  3 =:= 0, !, write('Fizz').
  fizzbuzz(X) :- X mod  5 =:= 0, !, write('Buzz').
  fizzbuzz(X) :- write(X).

  dofizzbuzz :-between(1, 100, X), fizzbuzz(X), nl, fail.
  dofizzbuzz.
  
  --------------------------------
  [[ Haskell ]]
  
  fizzbuzz :: Int -> String
  fizzbuzz x
    | f 15 = "FizzBuzz"
    | f  3 = "Fizz"
    | f  5 = "Buzz"
    | otherwise = show x
    where
      f = (0 ==) . rem x
  
  main :: IO ()
  main = mapM_ (putStrLn . fizzbuzz) [1 .. 100]
    
  --------------------------------
  [[ OCaml ]]
  
  let fizzbuzz i =
    match i mod 3, i mod 5 with
      0, 0 -> "FizzBuzz"
    | 0, _ -> "Fizz"
    | _, 0 -> "Buzz"
    | _    -> string_of_int i
   
  let _ =
    for i = 1 to 100 do print_endline (fizzbuzz i) done
    
  --------------------------------
  [[ Nix ]]
  
  let
    fizzbuzz = { x ? 1 }:
      ''
        ${if (mod x 15 == 0) then
          "FizzBuzz"
        else if (mod x 3 == 0) then
          "Fizz"
        else if (mod x 5 == 0) then
          "Buzz"
        else
          (toString x)}
      '' + (if (x < 100) then
        fizzbuzz { x = x + 1; } else "");
  in
  fizzbuzz { }
  
  --------------------------------
  [[ Elixir ]]
  
  1..100 |> Enum.map(fn i ->
    cond do
      rem(i,3\*5) == 0 -> "FizzBuzz"
      rem(i,3) == 0    -> "Fizz"
      rem(i,5) == 0    -> "Buzz"
      true             ->  i
    end
  end) |> Enum.each(fn i -> IO.puts i end)
  
  --------------------------------
  [[ J ]]
  
  (":[^:(0=#@])Fizz`Buzz;@#~0=3 5&|)"0>:i.100
  
  --------------------------------
  [[ Forth ]]
  
  : .fizzbuzz ( n -- )
    0 pad c!
    dup 3 mod 0= if s" Fizz" pad  place then
    dup 5 mod 0= if s" Buzz" pad +place then
    pad c@ if drop pad count type else . then ;
  
  : zz ( n -- )
    1+ 1 do i .fizzbuzz cr loop ;
  100 zz
  
  --------------------------------
  [[ Go ]]
  
  func main() {
      for i := 1; i <= 100; i++ {
          switch {
          case i%15==0:
              fmt.Println("FizzBuzz")
          case i%3==0:
              fmt.Println("Fizz")
          case i%5==0:
              fmt.Println("Buzz")
          default: 
              fmt.Println(i)
          }
      }
  }
  
  --------------------------------
  [[ C ]]
  
  int main (void)
  {
      int i;
      for (i = 1; i <= 100; i++)
      {
          if (!(i % 15))
              printf ("FizzBuzz");
          else if (!(i % 3))
              printf ("Fizz");
          else if (!(i % 5))
              printf ("Buzz");
          else
              printf ("%d", i);
  
          printf("\n");
      }
      return 0;
  }
  
  --------------------------------
  [[ Java ]]
  
  public class FizzBuzz {
      public static void main(String[] args) {
          for (int number = 1; number <= 100; number++) {
              if (number % 15 == 0) {
                  System.out.println("FizzBuzz");
              } else if (number % 3 == 0) {
                  System.out.println("Fizz");
              } else if (number % 5 == 0) {
                  System.out.println("Buzz");
              } else {
                  System.out.println(number);
              }
          }
      }
  }
  
  --------------------------------
  [[ Scala ]]
  
  object FizzBuzz extends App {
    1 to 100 foreach { n =>
      println((n % 3, n % 5) match {
        case (0, 0) => "FizzBuzz"
        case (0, _) => "Fizz"
        case (_, 0) => "Buzz"
        case  _     =>  n
      })
    }
  }


> But your comment is completely off-base.

I think it is rather your reply that is off-base; or else I have not made myself sufficiently clear.

My point was simply that the words used to describe the other courses are better fits for what SICP teaches than "procedural", which is a poor fit for describing Lisp-family languages and would make more sense applied to other contemporary languages like COBOL and FORTRAN (and of course typical Algol-family languages).

I understand perfectly well what "functional" means in the context of signals and systems. I took such a course in undergrad, 20+ years ago. But I was using abstract nouns there, rather than adjectives (and writing "function" rather than "functionality" would not really have resolved the issue).

The material in SICP deeply explores the functional programming idiom. A big part of the point of using a Lisp dialect is that functions are first-class (I've watched the OCW lectures; there's a whole section discussing what that means and entails) objects, which enables higher-order functions.

Nothing in my comment is about modelling anything to do with electronics in software.


You may want to take your issue with the use of the word "procedural" up with the authors of SICP:

> Underlying our approach to this subject is our conviction that “computer science” is not a science and that its significance has little to do with computers. The computer revolution is a revolution in the way we think and in the way we express what we think. The essence of this change is the emergence of what might best be called procedural epistemology—the study of the structure of knowledge from an imperative point of view, as opposed to the more declarative point of view taken by classical mathematical subjects. Mathematics provides a framework for dealing precisely with notions of “what is.” Computation provides a framework for dealing precisely with notions of “how to.” [Emphasis in original]

-- Preface to the First Edition


That does explain the use of the term. They are reasoning about the systems in terms of what will happen (its procedure), but still describing systems as compositions of parts (as nodes in an AST, effectively) rather than as lists of instructions. And they teach how to analyze problems in order to design systems that way. And, of course, writing the program is inherently a self-directed imperative; you can't simply learn how to write programs and have programs exist as a result — you have to take that initiative.


Your comments are clear enough; they're just mistaken.

Lisp dialects generally do not support mathematical functions, despite supporting the functional-programming idiom, which is inspired by mathematical functions. Rather, they support procedures, which in most Lisps are called "functions". In Scheme, however, the Lisp they chose for the course, they are called "procedures", an intentional choice to avoid creating precisely the kind of confusion you are experiencing. Lisp "functions", like procedures in most other languages, can fail to terminate, can raise an error, can have side effects, and can depend on mutable state.

Mathematical functions cannot do any of these things. If they could, it wouldn't make much sense to take their Laplace transforms!

The five chapters of SICP (I recommend http://sarabander.github.io/sicp/html/index.xhtml) are:

- 1 Building Abstractions with Procedures

- 2 Building Abstractions with Data

- 3 Modularity, Objects, and State

- 4 Metalinguistic Abstraction

- 5 Computing with Register Machines

— ⁂ —

You said:

> Nothing in my comment is about modelling anything to do with electronics in software.

You are mistaken about that. The part of your comment that is about modelling something to do with electronics in software is the part where you replied to a comment saying:

> ... four "deep dives" into the four "languages of engineering." There were four 15-unit courses, each about one of these "languages":

> - 6.001: Structure and Interpretation of Computer Programs (the "procedural" language, led by Abelson and Sussman)

> - 6.002: Circuits and Electronics ("structural" language)

> - 6.003: Signals and Systems ("functional" language)

> - 6.004: Computation Structures ("architectural" language)

Your comment in reply said:

> Lisp (...) can hardly be called "procedural". The core material of SICP revolves around (...) concepts that (...) have far more to do with "structure", "architecture" and "functionality" [sic] than with "procedure".

That is, you were explicitly asserting that the core material of SICP was concerned with "structure", "architecture", and "functions" in the sense of the core material of those courses, rather than only or even primarily procedural abstraction. However, two of those four courses—specifically, 6.002 and 6.004—were concerned almost exclusively with modeling electronics. (An awful lot of the "systems" in 6.003 are also electronic, but that's beside the point.) However, as you know, 6.001, SICP, and Lisp are concerned exclusively with modeling things in software.

Modeling electronics in software is a reasonable thing to do, and Lisp is a reasonable medium to do it in, but you need to understand the structural, architectural, and (at least for analog electronics) functional angles on the electronics in order to do that. None of that is part of SICP or 6.001, and Lisp is not a reasonable medium for describing electronic systems from at least the structural and functional angles. You need schematics, pole-zero diagrams, and Bode plots. If you remembered what you studied in that course 20+ years ago this would be obvious to you.


> The five chapters of SICP (I recommend http://sarabander.github.io/sicp/html/index.xhtml) are:

> - 1 Building Abstractions with Procedures

Where Abelson, Sussman & Sussman use the word "procedures" here, they mean what we would typically call "functions" today. Today, "procedural programming" basically means "imperative programming", and that is not the idiom they are teaching. (Where the exact term "procedure" is used nowadays — though it's less common now — it generally refers specifically to a function which does not return a usable value, which is called specifically for its side effects. SICP instead generally describes what we would now call "functional programming".)

> That is, you were explicitly asserting that the core material of SICP was concerned with "structure", "architecture", and "functions" in the sense of the core material of those courses

By "SICP" I clearly meant 6.001 and only 6.001, since that's the course titled as such ("SICP" stands for "Structure and Interpretation of Computer Programs").

I was not asserting that SICP was concerned with any term in the sense of the core material of any other course, which is why I didn't mention the other courses in that sentence. I was asserting that SICP was concerned with those concepts as they are commonly understood.

I wrote the comment knowing nothing of the content of the other courses, because nothing about the content of the other courses was relevant to the point I was making.

Please do not try to tell me what I meant by my own words.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: