Skip to content

Commit

Permalink
Even more koans fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
phoe committed May 6, 2020
1 parent aa735b3 commit 54bc26b
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 169 deletions.
22 changes: 12 additions & 10 deletions koans/control-statements.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,18 @@
;; See the License for the specific language governing permissions and
;; limitations under the License.

;; TODO return-from

(define-test test-if-then-else
(let ((result))
(if t
(setf result "true value")
(setf result "false value"))
(assert-equal result ____)
(if nil
(setf result "true value")
(setf result "false value"))
(assert-equal result ____)))
(let ((result))
(if t
(setf result "true value")
(setf result "false value"))
(assert-equal result ____)
(if nil
(setf result "true value")
(setf result "false value"))
(assert-equal result ____)))


(define-test test-when-and-unless
Expand Down Expand Up @@ -65,4 +67,4 @@
(setf x (+ 1 x))
nil
(setf x (+ 1 x)))
x)))
x)))
159 changes: 65 additions & 94 deletions koans/functions.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -98,112 +98,83 @@
;; A &rest parameter must come before &key parameters.
(list a b c c-provided-p x))

(define-test test-many-kinds-params
(define-test funky-parameters
(assert-equal (func-with-funky-parameters 1) ___)
(assert-equal (func-with-funky-parameters 1 :b 2) ___)
(assert-equal (func-with-funky-parameters 1 :b 2 :c 3) ___)
(assert-equal (func-with-funky-parameters 1 :c 3 :b 2) ___))

(define-test test-lambdas-are-nameless-functions
"A lambda form defines a function, but with no name. It is possible
to execute that function immediately, or put it somewhere for later use."
(assert-equal 19 ((lambda (a b) (+ a b)) 10 9))
(let ((my-function))
(setf my-function (lambda (a b) (* a b)))
(assert-equal ___ (funcall my-function 11 9)))
(let ((list-of-functions nil))
(push (lambda (a b) (+ a b)) list-of-functions)
(push (lambda (a b) (* a b)) list-of-functions)
(push (lambda (a b) (- a b)) list-of-functions)
(assert-equal ___ (funcall (second list-of-functions) 2 33))))

(define-test test-lambdas-can-have-optional-params
(define-test lambda
;; A list form starting with the symbol LAMBDA denotes an anonymous function.
;; It is possible to call that function immediately or to store it for later
;; use.
(let ((my-function (lambda (a b) (* a b))))
(assert-equal ____ (funcall my-function 11 9)))
;; A LAMBDA form is allowed to take the place of a function name.
(assert-equal ____ ((lambda (a b) (+ a b)) 10 9))
(let ((functions (list (lambda (a b) (+ a b))
(lambda (a b) (- a b))
(lambda (a b) (* a b))
(lambda (a b) (/ a b)))))
(assert-equal ____ (funcall (first functions) 2 33))
(assert-equal ____ (funcall (second functions) 2 33))
(assert-equal ____ (funcall (third functions) 2 33))
(assert-equal ____ (funcall (fourth functions) 2 33))))

(define-test lambda-with-optional-parameters
(assert-equal ___ ((lambda (a &optional (b 100)) (+ a b)) 10 9))
(assert-equal ___ ((lambda (a &optional (b 100)) (+ a b)) 10)))


; returns sign x
(defun sign-of (x) (if (< x 0) (return-from sign-of -1)) (if (eq x 0) (return-from sign-of 0)) 1)

(define-test test-return-from-function-early
(assert-equal (sign-of -5.5) ___)
(assert-equal (sign-of 0) ___)
(assert-equal (sign-of ___) 1))


;; ----


;; Lambdas create "lexical closures", meaning that the resulting function, when
;; called, will execute in an environment wherein the lexical bindings to all
;; referred to names still apply.
;; This example from "Common Lisp The Language" Ch. 7

(defun adder (x)
"The result of (adder n) is a nameless function with one parameter.
This function will add n to its argument."
(defun make-adder (x)
;; MAKE-ADDER will create a function that closes over the parameter X.
;; The parameter will be remembered as a part of the environment of the
;; returned function, which will continue refering to it.
(lambda (y) (+ x y)))

(define-test test-lexical-closure-over-adder ()
(let ((add-100 (adder 100))
(add-500 (adder 500)))
"add-100 and add-500 now refer to different bindings to x"
(assert-equal ___ (funcall add-100 3))
(assert-equal ___ (funcall add-500 3))))


;; ----


;; The closure gives the returned function access to the bindings, not just the
;; values. This means that two functions which close over the same variables
;; will always see the same values of those variables if one does a setq.
(define-test lexical-closures
(let ((adder-100 (make-adder 100))
(adder-500 (make-adder 500)))
;; ADD-100 and ADD-500 now close over different values.
(assert-equal ____ (funcall adder-100 3))
(assert-equal ____ (funcall adder-500 3))))

(defun two-funs (x)
"Returns a list of two functions.
The first takes no parameters and returns x.
The second takes one parameter, y, and resets x to the value of y."
(defun make-reader-and-writer (x)
;; Both returned functions will refer to the same place.
(list (function (lambda () x))
(function (lambda (y) (setq x y)))))

(define-test test-lexical-closure-interactions
"An illustration of how lexical closures may interact."
(let ((tangled-funs-1 (two-funs 1))
(tangled-funs-2 (two-funs 2)))
(assert-equal (funcall (first tangled-funs-1)) ___)
(funcall (second tangled-funs-1) 0)
(assert-equal (funcall (first tangled-funs-1)) ___)

(assert-equal (funcall (first tangled-funs-2)) ___)
(funcall (second tangled-funs-2) 100)
(assert-equal (funcall (first tangled-funs-2)) ___)))


(define-test test-apply-function-with-apply
"APPLY calls the function parameter on a list of all the remaining
parameters"
(let (f1 f2 f3)
(setq f1 '+)
(setq f2 '-)
(setq f3 'max)

(assert-equal ___ (apply f1 '(1 2)))
(assert-equal ___ (apply f2 '(1 2)))

; after the function name, the parameters are consed onto the front
; of the very last parameter
(assert-equal ___ (apply f1 1 2 '(3)))
(assert-equal ___ (apply f3 1 2 3 4 '()))))


(define-test test-apply-function-with-funcall
"FUNCALL calls the function parameter on a list of all the remaining
parameters. Remaining params do not expect a final list."
(let (f1 f2 f3)
(setq f1 '+)
(setq f2 '-)
(setq f3 'max)
(assert-equal ___ (funcall f1 1 2))
(assert-equal ___ (funcall f2 1 2))
(assert-equal ___ (funcall f1 1 2 3))
(assert-equal ___ (funcall f3 1 2 3 4))))
;; The macro DESTRUCTURING-BIND is like LET, except it binds the variables
;; listed in its first argument to the parts of the list returned by the form
;; that is its second argument.
(destructuring-bind (reader-1 writer-1) (make-reader-and-writer 1)
(destructuring-bind (reader-2 writer-2) (make-reader-and-writer :one))
(assert-equal ____ (funcall reader-1))
(funcall writer-1 0)
(assert-equal ____ (funcall reader-1))
;; The two different function pairs refer to different places.
(assert-equal ____ (funcall reader-2))
(funcall writer-2 :zero)
(assert-equal ____ (funcall reader-2))))

(define-test apply
;; The function APPLY applies a function to a list of arguments.
(let ((function (lambda (x y z) (+ x y z))))
(assert-equal ____ (apply function '(100 20 3))))
;; FUNCTION is a special operator that retrieves function objects, defined
;; both globally and locally. #'X is syntax sugar for (FUNCTION X).
(assert-equal ____ (apply (function +) '(1 2)))
(assert-equal ____ (apply #'- '(1 2)))
;; Only the last argument to APPLY must be a list.
(assert-equal ____ (apply #'+ 1 2 '(3)))
(assert-equal ____ (apply #'max 1 2 3 4 '())))

(define-test funcall
;; The function FUNCALL calls a function with arguments, not expecting a final
;; list of arguments.
(let ((function (lambda (x y z) (+ x y z))))
(assert-equal ____ (funcall function 300 20 1)))
(assert-equal ____ (funcall (function +) 1 2))
(assert-equal ____ (funcall #'- 1 2))
(assert-equal ____ (funcall #'+ 1 2 3))
(assert-equal ____ (funcall #'max 1 2 3 4)))
2 changes: 1 addition & 1 deletion koans/multiple-values.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

(define-test binding-and-setting-multiple-values
;; The macro MULTIPLE-VALUE-BIND is like LET, except it binds the variables
;; listed in its first argument to the values returned by the form in its
;; listed in its first argument to the values returned by the form that is its
;; second argument.
(multiple-value-bind (x y) (next-fib 3 5)
(let ((result (* x y)))
Expand Down
123 changes: 59 additions & 64 deletions koans/strings.lisp
Original file line number Diff line number Diff line change
@@ -1,78 +1,73 @@
;; Copyright 2013 Google Inc.
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;; http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.
;;; Copyright 2013 Google Inc.
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;; http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.

(define-test test-double-quoted-strings-are-strings
(let ((my-string "do or do not"))
(true-or-false? ___ (typep my-string 'string))
"strings are the same thing as vectors of characters"
(true-or-false? ___ (typep my-string 'array))
(assert-equal (aref "meat" 2) (aref "fiesta" 5))
"strings are not integers :p"
(true-or-false? ___ (typep my-string 'integer))))
(define-test what-is-a-string
(let ((string "Do, or do not. There is no try."))
(true-or-false? ____ (typep string 'string))
;; Strings are vectors of characters.
(true-or-false? ____ (typep string 'array))
(true-or-false? ____ (typep string 'vector))
(true-or-false? ____ (typep string '(vector character)))
(true-or-false? ____ (typep string 'integer))))

(define-test multiline-string
;; A Lisp string can span multiple lines.
(let ((string "this is
a multi
line string"))
(true-or-false? ___ (typep string 'string))))

(define-test test-multi-line-strings-are-strings
(let ((my-string "this is
a multi
line string"))
(true-or-false? ___ (typep my-string 'string))))
(define-test escapes-in-strings
;; Quotes and backslashes in Lisp strings must be escaped.
(let ((my-string "this string has one of these \" and a \\ in it"))
(true-or-false? ____ (typep my-string 'string))))

(define-test substrings
;; Since strings are sequences, it is possible to use SUBSEQ on them.
(let ((string "Lorem ipsum dolor sit amet"))
(assert-equal ____ (subseq string 12))
(assert-equal ____ (subseq string 6 11))
(assert-equal ____ (subseq string 1 5))))

(define-test test-escape-quotes
(let ((my-string "this string has one of these \" in it"))
(true-or-false? ___ (typep my-string 'string))))


; This test from common lisp cookbook
(define-test test-substrings
"since strings are sequences, you may use subseq"
(let ((my-string "Groucho Marx"))
(assert-equal "Marx" (subseq my-string 8))
(assert-equal (subseq my-string 0 7) ____)
(assert-equal (subseq my-string 1 5) ____)))

(define-test test-accessing-individual-characters
"char literals look like this"
(true-or-false? ___ (typep #\a 'character))
(true-or-false? ___ (typep "A" 'character))
(true-or-false? ___ (typep #\a 'string))
"char is used to access individual characters"
(define-test strings-versus-characters
;; Strings and characters have distinct types.
(true-or-false? ____ (typep #\a 'character))
(true-or-false? ____ (typep "A" 'character))
(true-or-false? ____ (typep #\a 'string))
;; One can use both AREF and CHAR to refer to characters in a string.
(let ((my-string "Cookie Monster"))
(assert-equal (char my-string 0) #\C)
(assert-equal (char my-string 3) #\k)
(assert-equal (char my-string 7) ___)))

(assert-equal ____ (char my-string 0))
(assert-equal ____ (char my-string 3))
(assert-equal ____ (aref my-string 7))))

(define-test test-concatenating-strings
"concatenating strings in lisp is a little cumbersome"
(let ((a "this")
(b "is")
(c "unwieldy"))
(assert-equal ___ (concatenate 'string a " " b " " c))))

;; Concatenating strings in Common Lisp is possible, if a little cumbersome.
(let ((a "Lorem")
(b "ipsum")
(c "dolor"))
(assert-equal ____ (concatenate 'string a " " b " " c))))

(define-test test-searching-for-characters
"you can use position to detect characters in strings
(or elements of sequences)"
(assert-equal ___ (position #\b "abc"))
(assert-equal ___ (position #\c "abc"))
(assert-equal ___ (find #\d "abc")))

;; The function POSITION can be used to find the first position of an element
;; in a sequence. If the element is not found, NIL is returned.
(assert-equal ____ (position #\b "abc"))
(assert-equal ____ (position #\c "abc"))
(assert-equal ____ (position #\d "abc")))

(define-test test-finding-substrings
"search finds subsequences"
;; The function SEARCH can be used to search a sequence for subsequences.
(let ((title "A supposedly fun thing I'll never do again"))
(assert-equal 2 (search "supposedly" title))
(assert-equal 12 (search "CHANGETHISWORD" title))))
(assert-equal ____ (search "supposedly" title))
(assert-equal 12 (search ____ title))))

0 comments on commit 54bc26b

Please sign in to comment.