'Build Your Own Lisp' Solutions: 4.4

Q: What does the \n mean in those strings?


A: '\n' signifies a newline character, so the startup information doesn't appear on the same line as the first prompt.



'Build Your Own Lisp' Solutions: 4.3

Q: Add an extra message to the Version and Exit Information.


A:

...
int main(int argc, char** argv) {

  puts("Lispy Version 0.0.0.0.1, Something Something Something");
  puts("Press Ctrl+c to Exit. Happy Trails!\n");

  while (1) {

    /* Now in either case readline will be correctly defined */
    char* input = readline("lispy> ");
    add_history(input);

    printf("No you're a %s\n", input);
    free(input);

  }

  return 0;
}
...


'Build Your Own Lisp' Solutions: 4.2

Q: Change what is echoed back to the user.


A:

...
  while (1) {
    
    /* Now in either case readline will be correctly defined */
    char* input = readline("something of my choice> ");
    add_history(input);

    printf("%s\n", input);
    free(input);
    
  }
...


'Build Your Own Lisp' Solutions: 4.1

Q: Change the prompt from "lispy>" to something of your choice.


A:

...
  while (1) {
    
    char* input = readline("something of my choice> ");
    add_history(input);

    printf("No you're a %s\n", input);
    free(input);
    
  }
...


'Build Your Own Lisp' Solutions: 3.12

Q: What does the 'typedef' keyword do exactly?


A: 'typedef' lets you define a type, which is to say, it lets you give a new name to a pre-existing type (which can be useful for organizational/readability purposes), or to define a struct as a new type, unique to your program.



SICP Solutions - 1.8

Q: Newton's method for cube roots is based on the fact that if y is an approximation to the cube root of x, then a better approximation is given by the value:

Use this formula to implement a cube-root procedure analogous to the square-root procedure. (In section 1.3.4 we will see how to implement Newton's method in general as an abstraction of these square-root and cube-root procedures.)


A:

;; The setup is the same, except for the names.
(define (cbrt-iter guess x)
  (if (good-enough? guess x)
    guess
    (cbrt-iter (improve guess x)
               x)))

(define (cube x)
  (* x x x))

(define (good-enough? guess x)
  (< (abs (- (cube guess) x)) 0.001))

(define (cbrt x)
  (cbrt-iter 1.0 x))

;; The formula in scheme.
(define (improve guess x)
  (/ 
    (+ (/ x (* guess guess)) (* 2 guess))
    3))

;; A few guesses.
(display (cbrt 8))
(newline)
(display (cbrt 27))
(newline)
(display (cbrt 60))
(newline)
2.0000049116755
3.00000054106418
3.91487458417134 ; My calculator gives 3.91486764117


'Build Your Own Lisp' Solutions: 3.11

Q: What is the continue keyword and what does it do?


A: In a while or for loop, 'continue' will skip the rest of the block and go straight to the next iteration of the loop. Here is a program that counts to twenty, using 'continue' to filter out undesirable multiples of three:

#include <stdio.h>

int main(void)
{
  int i = 0;

  while (++i <= 20) {
    if (i % 3 == 0) {
      continue;
    }
    printf("%d\n", i);
  }

  return 0;
}
1
2
4
5
7
8
10
11
13
14
16
17
19
20


'Build Your Own Lisp' Solutions: 3.10

Q: What is the break keyword and what does it do?


A: Break breaks out of a while loop or a for loop, from within the body of that loop. Here is a program that will run a loop over nine quintillion times on most computers, before the number gets too bug for 'unsigned int' and goes back to zero:

#include <stdio.h>

int main(void)
{
  unsigned int i = 0;

  while (++i) {
    printf("%d: Looping...\n", i);
  }

  return 0;
}
1: Looping...
2: Looping...
3: Looping...
4: Looping...
5: Looping...
6: Looping...
7: Looping...
8: Looping...
9: Looping...
10: Looping...
...
9223372036854775806: Looping...

Since nine quintillion is overkill for most programs, we can use a break statement to stop it at, say, three.

#include <stdio.h>

int main(void)
{
  unsigned int i = 0;

  while (++i) {
    printf("%d: Looping...\n", i);
    if (i == 3) {
      break;
    }
  }

  return 0;
}
1: Looping...
2: Looping...
3: Looping...


'Build Your Own Lisp' Solutions: 3.9

Q: What is the switch statement and how does it work?

A: A switch statement syntactic sugar for certain combinations of 'if' and 'else', which is typically used where there are very many different possible conditions.

It is wildly controversial. Some feel that it is extremely convenient and clear, others feel that it can cause unexpected bugs (and they dislike it for other reasons a bit too technical for this post). I'm part of the former group, but I sympathize with the latter.

Here is an example:

#include <stdio.h>

void c_finder(char c)
{
  switch(c) {
    case 'a':
    case 'b':
      printf("The letter is too small!\n");
      break;
    case 'c':
      printf("The letter is just right!\n");
      break;
    default:
      printf("The letter is too large!\n");
  }
}

int main(void)
{
  c_finder('a');
  c_finder('b');
  c_finder('c');
  c_finder('z');

  return 0;
}
The letter is too small!
The letter is too small!
The letter is just right!
The letter is too large!

That switch statement is equivalent to:

  if (c == 'a' || c == 'b') {
    printf("The letter is too small!\n");
  } else if (c == 'c') {
    printf("The letter is just right!\n");
  } else {
    printf("The letter is too large!\n");
  }

Notice that 'switch' only tests equality with a constant. Something like 'else if (a > b)' doesn't really have a direct equivalent.

The reason some people dislike switch is the fall-through behaviour in the example. If a case is true, switch will execute all code down to the next 'break'. If you forget to write your breaks, you can end up with unexpected bugs. I think switch can be a useful tool, and can make code more readable, but caution and discipline are heavily recommended.