Created
October 23, 2018 10:59
-
-
Save JonNorman/5b588c8ea853b15459d96a6f55a56fae to your computer and use it in GitHub Desktop.
A quick overview of the concepts covered in week 3 of scala-school
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************************** | |
* Control structures | |
* | |
* Control structures are bits of code that determine "where" your program goes - it | |
* isn't that useful having a program that does the same thing every time you run it, | |
* you want to be able to specify conditions and checks and for it to act according to | |
* those results | |
**************************************************************************************/ | |
/* | |
If statements are the main way that we follow different behaviour based on some condition. | |
They require: | |
A condition - some expression that returns a Boolean value (Boolean = true or false) | |
The 'true' code - what to do if the condition returns true | |
(Optional) The 'else' or 'false" code - what to do if the condition returns false | |
Note: if you don't provide an 'else' block and none of the if statements above match then | |
nothing will be executed. | |
*/ | |
def adviseMeOnMyPacking(expectedWeather: String): String = | |
if (expectedWeather == "Rainy") { | |
"Take an umbrella" | |
} else { | |
"Pack your shorts" | |
} | |
// let's define a list of various weather types... | |
val variousWeathers = List( | |
"Rainy", | |
"Sunny", | |
"Snowy", | |
"Icy", | |
"Something completely unrelated to weather") | |
// let's see what advice we get by iterating over those weathers with 'foreach' and printing the results... | |
variousWeathers.foreach(weather => | |
println(adviseMeOnMyPacking(weather))) | |
/* | |
We could make our function better by listing more of the types of weather we expect and chaining some | |
more 'else if' statements on, finally ending in our catch-all 'else' block. | |
*/ | |
def adviseMeOnMyPacking2(expectedWeather: String): String = | |
if (expectedWeather == "Rainy") { | |
"Take an umbrella" | |
} else if (expectedWeather == "Sunny") { | |
"Pack your shorts" | |
} else if (expectedWeather == "Snowy" || expectedWeather == "Icy"){ | |
"Pack your gloves and crampons" | |
} else { | |
"No idea what you're talking about mate, try again" | |
} | |
// let's see what we get now... | |
variousWeathers.foreach(weather => | |
println(adviseMeOnMyPacking2(weather))) | |
/* | |
Before we go on, we should quickly recap how we can work with Booleans, after all these | |
will drive where our programs go and how they operate. Just what can we express? | |
*/ | |
// we have the literal boolean values | |
if (true) { | |
println("This will always be executed") | |
} else { | |
println("This blocked will NEVER be reached") | |
} | |
// we have the "NOT" operator: ! which inverts the Boolean value it is applied to | |
if(!true) { | |
println("Now this will never be reached: not true is always false!") | |
} else { | |
println("This will always be reached: not false is always true") | |
} | |
// we can combine Boolean values together and it works logically as if you were saying it | |
def tellMeWhatTheyAreLike(isOld: Boolean, isEmployed: Boolean, doesDance: Boolean): String = { | |
// here we use double ampersand (&&) to mean AND; if BOTH conditions are true then it is true, otherwise false | |
if (isOld && isEmployed && doesDance) { | |
"a work-hard play-hard long-in-the-tooth tap dancer" | |
// here we use double pipe (||) to mean OR; if EITHER condition is true, then it is true, otherwise false | |
} else if (!doesDance || isOld) { | |
"a non-dancer or an older person" | |
} else if (!doesDance && (!isOld || isEmployed)){ | |
"non-dancing youth or worker" | |
} else { | |
"a person I can't describe" | |
} | |
} | |
tellMeWhatTheyAreLike(true, true, true) | |
tellMeWhatTheyAreLike(false, true, true) | |
tellMeWhatTheyAreLike(false, true, false) | |
/* | |
We can also use the CASE statement to do pattern matching. In this example, it will seem | |
slightly contrived but it will have great benefit later when we define our own types and | |
want to match on subtypes. | |
*/ | |
/* here we put our values into a Tuple3 and we match on that tuple. In each case statement we | |
can say what the values inside this Tuple are expected to be and then provide the result based on that. | |
Note: the underscore (_) is used here to indicate that we don't care about a value - it is a throwaway | |
*/ | |
def tellMeWhatTheyAreLike2(isOld: Boolean, isEmployed: Boolean, doesDance: Boolean): String = { | |
(isOld, isEmployed, doesDance) match { | |
case (true, true, true) => "a work-hard play-hard long-in-the-tooth tap dancer" | |
case (true, _, _) => "a non-dancer or an older person" | |
case (_, _, false) => "a non-dancer or an older person" | |
case (false, _ ,false) => "non-dancing youth or worker" | |
case (_, true ,false) => "non-dancing youth or worker" | |
case _ => "a person I can't describe" // here we don't provide any constraints on the case, ANYTHING will match | |
} | |
} | |
/* the above isn't great, it is more typing and we have repeated ourselves a fair amount | |
You can actually add conditions on your case statements | |
*/ | |
def tellMeWhatTheyAreLike3(isOld: Boolean, isEmployed: Boolean, doesDance: Boolean): String = { | |
(isOld, isEmployed, doesDance) match { | |
case (true, true, true) => "a work-hard play-hard long-in-the-tooth tap dancer" | |
case _ if !doesDance || isOld => "a non-dancer or an older person" | |
case (_, _, false) if !isOld || isEmployed => "non-dancing youth or worker" | |
case _ => "a person I can't describe" | |
} | |
} | |
/* If these case statements look a little contrived it is because they are! But this pattern matching | |
* paradigm becomes really useful when we start using custom types a little more. */ | |
/* | |
There are other control structures you might know from other languages such as the 'while' loop | |
but we won't go over them here - the 'while' loop is rarely used as there are more 'functional' | |
ways of iterating such as `fold`, `map`, `foreach` etc. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment