layout | title | permalink |
---|---|---|
default |
Flow Control |
/outline/flow_control.html |
{::options parse_block_html="true" /}
{% comment %}
http://clojurebridge.github.io/curriculum/outline/flow_control.html
{% endcomment %}
if
cond
- Boolean logic
"Flow control" is the programming term for deciding how to react to a given circumstance. We make decisions like this all the time. If it's a nice day out, then we should visit the park; otherwise we should stay inside and play board games. If your car's tank is empty, then you should visit a gas station; otherwise you should continue to your destination. {: ng-show="block11" .description}
Software is also full of these decisions. If the user's input is valid, then we should save her data; otherwise we show an error message. The common pattern here is that you test some condition and react differently based on whether the condition is true or false. {: ng-show="block12" .description}
In Clojure, the most basic tool we have for the flow control is the
if
operator. Here's the example how you might code the data validation scenario. {: ng-show="block21" .description}
Here' an example. If adding 40 to
y
is still less than 150, then return(+ y 40)
; otherwise, returns -150. (As for turtle app's frame, the top has 150 in y, while the bottom has -150 in y.) {: ng-show="block22" .description}
Reference: Conditional
if
{: ng-show="block22" .description}
(if (< (+ y 40) 150)
(+ y 40)
-150))
(if conditional-expression
expression-to-evaluate-when-true
expression-to-evaluate-when-false)
(if (> 3 1)
"3 is greater than 1"
"3 is not greater than 1")
;=> "3 is greater than 1"
(if (> 1 3)
"1 is greater than 3"
"1 is not greater than 3")
;=> "1 is not greater than 3"
When testing the truth of an expression, Clojure considers the values
nil
andfalse
to be false and everything else to be true. Here are some examples: {: ng-show="block51" .description}
Reference: Truthiness {: ng-show="block51" .description}
(if "anything other than nil or false is considered true"
"A string is considered true"
"A string is not considered true")
;=> "A string is considered true"
(if nil
"nil is considered true"
"nil is not considered true")
;=> "nil is not considered true"
(if (get {:a 1} :b)
"expressions which evaluate to nil are considered true"
"expressions which evaluate to nil are not considered true")
;=> "expressions which evaluate to nil are not considered true"
-
Write a function
y-within-frame
that takes y (vertical position) as an argument. -
You may use if example in the slide.
-
The function should return the y value that won't exceed 150.
;; if example
(if (< (+ y 40) 150)
(+ y 40)
-150))
;; usage of y-within-frame function
(y-within-frame 80) ;=> 120
(y-within-frame 180) ;=> -150
The
if
operator takes only one predicate. When we want to use multiple predicates,if
is not a good option. We have to write nested, nested, ... and nestedif
conditions. To branch to multiple situations,cond
operator works well. {: ng-show="block61" .description}
Here's the example. If adding 40 to y exceeds 150, evaluate the first form. In this case, it returns -150. If adding 40 to y is less than -150, evaluate the second form. In this case, it returns 150. If both two predicates return false, evaluate the
:else
form. In this case, it returns y plus 40. If we use this function in the turtle app, we can keep our turtle between top and bottom of the frame. {: ng-show="block62" .description}
Reference: Conditional
cond
{: ng-show="block62" .description}
(cond
(> (+ y 40) 150) -150
(< (+ y 40) -150) 150
:else (+ y 40)))
(cond
predicate1 expression-to-evaluate-when-predicate1-is-true
predicate2 expression-to-evaluate-when-predicate2-is-true
...
:else expression-to-evaluate-when-all-above-are-false)
The function we wrote in the previous exercise,
y-within-frame
, has a flaw. If the given y value is -1000, the function will return -960. Since y value of the frame bottom is -150, -960 is beyond that. Your turtle will go invisible area. Let's make it real within-frame function usingcond
.
-
Write a function
y-within-frame-cond
that takes y (vertical position) as an argument. -
You may use
cond
example in the slide. -
The function should return the y value between -150 and 150.
;; usage of y-within-frame-cond function
(y-within-frame-cond 200) ;=> -150
(y-within-frame-cond -200) ;=> 150
(y-within-frame-cond 0) ;=> 40
if
statements are not limited to testing only one thing. You can test multiple conditions using boolean logic. Boolean logic refers to combining and changing the results of predicates usingand
,or
, andnot
. {: ng-show="block81" .description}
If you've never seen this concept in programming before, remember that it follows the common sense way you look at things normally. Is this and that true? Only if both are true. Is this or that true? Yes, if either -- or both! -- are. Is this not true? Yes, if it's false. {: ng-show="block81" .description}
and
,or
, andnot
work like other functions (they aren't exactly functions, but work like them), so they are in prefix notation, like we've seen with arithmetic. {: ng-show="block91" .description}
x | y | (and x y) |
(or x y) |
(not x) |
(not y) |
---|---|---|---|---|---|
false | false | false | false | true | true |
true | false | false | true | false | true |
true | true | true | true | false | false |
false | true | false | true | true | false |
and
,or
, andnot
can be combined. This can be hard to read. Here's an example: {: ng-show="block101" .description}
(defn leap-year?
"Every four years, except years divisible by 100, but yes for years divisible by 400."
[year]
(and (zero? (mod year 4))
(or (zero? (mod year 400))
(not (zero? (mod year 100))))))
We have learned
cond
,and
,or
, andnot
. Let's think what function we can write combining those. Here's an example: {: ng-show="block110" .description}
(defn true-or-false?
"Given op, returns true or false"
[op]
(let [x true
y false]
(cond
(= op :and) (and x y)
:else false)))
(defn correct?
"Given op and ans, returns message whether ans was correct or not"
[op ans]
(if (= ans (true-or-false? op))
"You won"
"You lost"))
true-or-false?
function in previous slide sees only:and
operation. Add:or
,:not
operation in the function.
- Use
core.clj
ofmyproject
and InstaREPL - Add
(= op :or)
and(= op :not)
incond
- For
:not
, choose either x or y for the argument
;; usage of correct? function
(correct? :and false) ;=> "You won"
(correct? :or false) ;=> "You lost"
(correct? :not true) ;=> "You won" (this may be "You lost")
{% comment %}
🌟 A link below is for a slide only. Go to README.md instead. 🌟
{% endcomment %}