<jupyter_start><jupyter_text>Expressions=====================An Expression in F is a collection of values, variables, functions and operators that combined together produces a definite value. This means that expressions themselves can be used in other expressions.for example<jupyter_code>2 + 2<jupyter_output><empty_output><jupyter_text>In F expressions can be joined together using a semi-colon or a new line. This creates a bigger expression whose value is the value of the last expression<jupyter_code>2 + 2; 3 * 2;<jupyter_output><empty_output><jupyter_text>You can have multiple expressions combined by putting them on a new line<jupyter_code>let a = 
    2 + 2
    3 * 2
a<jupyter_output><empty_output><jupyter_text>Unit ValueIn F there is a special value called `unit` It's a single value represented by `()` and has a type of `unit`. Unit is a special value because it represent the idea of "Nothing" not "Null".. "Nothing" or in many other languages "Void". In F all expressions **MUST** return a value. So for expressions that don't have anything to return, they return Unit instead.This is important because unit is a value like any other value we looked at in the previous lesson. This means that you can have `Array` amongst other things.<jupyter_code>let z = ()
z<jupyter_output><empty_output><jupyter_text>Because `unit` is a unique kind of value that we don't need, assigning it to a named value like `z` is overkill at best. In situations like these we use the `do` keyword to indicate that the expression returns `unit` and that we don't care about the value of the expression. so the previous example can now be described as<jupyter_code>do ()<jupyter_output><empty_output><jupyter_text>Unit is also the return type for expressions that are expected to have no value like assignment of values to variables<jupyter_code>let mutable myVariable = 0

//The type of unitVariable is unit
let unitVariable = myVariable <- 10 

//The expression can be simplified as    
do myVariable <- 12<jupyter_output><empty_output><jupyter_text>Basic ExpressionsIn this tutorial we'll look at the following types of expressions1. if-expressions2. match expressions3. for expressions4. while expression5. List comprehensions6. Sequences  If ExpressionIn F an if expression can return either one of two expressions depending on the result of a condition expression. the general syntax is ```fsharpif boolean-expression then expression1 [ else expression2 ]```where the condition is any expression that evaluates to a boolean value (true or false). If the value is true then the value of the If statement becomes the value of `expression1` otherwise the value becomes the value of `expression2`<jupyter_code>let x = 10
if x > 3 then 1 else 2<jupyter_output><empty_output><jupyter_text>Since the If expression is also an expression, we can assign it's value to another label<jupyter_code>let ifResult = if x > 3 then 1 else 2
ifResult<jupyter_output><empty_output><jupyter_text>Because If is an expression, the return type of both `expression1` and `expression2` **MUST** be of the same type of expression so you can't have `expression1` evalute to an `int` and `expression2` evalute to a `string` for example<jupyter_code>if x > 3 then 1 else "two"; 2<jupyter_output><empty_output><jupyter_text>The slight exception to this rule is that You can omit the `else` branch of the expression `if` branch of the expression returns `unit`.<jupyter_code>if x > 3 then ()<jupyter_output><empty_output><jupyter_text>That's because the compiler will just fill in the else branch for you like so<jupyter_code>if x > 3 then () else ()<jupyter_output><empty_output><jupyter_text>Match Expressions Match Expressions are like if expressions but they go way beyond the scope of IF expressions. It's one of the major ways of doing pattern matching. [Pattern Matching](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching) is topic we will visit multiple times through out this course. But we will keep things simple for now.A match expression simply evaluates if a value "matches" an pattern and if it does, the expression assigned to that pattern is evaluated.```fsharpmatch  with|  -> |  -> ...```<jupyter_code>let a = 2
match a with
| 1 -> "The value is 1"
| 2 -> "The value is 2"
| 3 -> "The value is 3"
| _ -> "The value is not 1 2 or 3"<jupyter_output><empty_output><jupyter_text>The match expression compares a to 1 and if it matches, It returns  "The value is 1" as the value of the match expression. If it doesn't match, It moves on to the next pattern and so on and so forthThe last line has something called the "wildcard pattern". This pattern matches any and everything.This line is necessary because F has something called _"exhaustive pattern matching"_ which means that the compiler makes sure that there are no cases that we might have forgotten. This is useful if you are matching on a value that has finite posibilites like Discriminated Unions but we'll see discrimintated Unions in a later lesson.The wildcard pattern essentially switches off exhaustive pattern matching so you should think carefully before applying the pattern. In the above case, we can't write a unique case for all approx 6 Billion posibilities of `int32` so we have to use it  FiltersEach pattern in the match expression could have a filter that is evaluated after a match has been found in order to narrow down the match. Like with the if expression, the filter is a boolean expression (evaluates to either true or false)The form is as follows```fsharpmatch  with|  when  -> ```<jupyter_code>let number = 125

match number with
| n when n % 2 = 0 -> "The number is an even number"
| n -> "The number is an odd number"<jupyter_output><empty_output><jupyter_text>In this example, we make use of a "Variable Pattern" similar to what we learnt about binding in the previous lesson the value number is **bound** to the identifer n. After that the filter `n % 2 = 0` is then evaluated and if it is true, the expression is then evaluated otherwise, it falls through to the next pattern   For Expressions The `if` and `match` expressions are mainly about making decisions. The `for` expression is about doing repititions. The general form of the `for` expression is as follows```fsharpfor identifier = start [ to | downto ] finish do    body-expression```for example<jupyter_code>let mutable total = 0
    
// 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10    
for i = 0 to 10 do
    total <- total + i
    
total<jupyter_output><empty_output><jupyter_text>In this example, the identifier `i` starts at 0 the body of the expression is evaluated and then i incremented by 1 each time it gets to 10. During each iteration we mutate the variable total by first getting the original value and adding `i` to it.Keep in mind that the value of the body expression **MUST** be `unit`. Because the value of an assignment expression is unit, it compiles just fine. This indirectly means that the result of a for expression is also `unit`To do the same thing in the reverse order we use `downto` instead of `to`<jupyter_code>let mutable total = 0
    
// 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1    
for i = 10 downto 0 do
    total <- total + i
total<jupyter_output><empty_output><jupyter_text>A different form of the for in iterates of lists, arrays, ranges or any enumerable expression (more on that later). The structure is as follows```fsharpfor pattern in enumerable-expression do    body-expression```<jupyter_code>let mutable total = 0

// 1 + 3 + 5 + 7 + 9    
for i in 1 .. 2 .. 10 do
    total <- total + i

total<jupyter_output><empty_output><jupyter_text>While Expression The while expression continues to evaluate an expression until a test expression becomes false. It has the form```fsharpwhile test-expression do    body-expression```The key distinction between the while expression and the for expression is a for expression is said that to be bounded meaning that it has a definite end. The while expression on the other hand can be unbounded meaning that if the test expression never evaluates to false, the loop will run forever. This distinction is useful and will definitely come in handy later<jupyter_code>let mutable total = 0
let mutable i = 1
// 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
while i <= 10 do
    total <- total + i
    i <- i + 1

total<jupyter_output><empty_output><jupyter_text>List ComprehensionInstead of using looping expressions to mutate variables, we could use then to generate datastructures like Lists and Arrays. This is with a `yield` keyword which produces the next element in the sequence.<jupyter_code>[ for i in 0 .. 5 do yield i ]<jupyter_output><empty_output><jupyter_text>or if you want to get an array<jupyter_code>[| for i in 0..5 do yield i |]<jupyter_output><empty_output><jupyter_text>Because the pattern above is very common, It can be shortened to<jupyter_code>[ for i in 0..5 -> i ]<jupyter_output><empty_output><jupyter_text>We can also use while loops inside list comprehensions<jupyter_code>let mutable i = 1
[ while i < 10 do i <- i + 1; yield i ]<jupyter_output><empty_output><jupyter_text>Sequence Expressions A sequence expression is a lazily evaluted series of items all of the same type. Lazy evaluation means that each value in the sequence expression is only produced on demand. Sequences in F map to the dotnet `IEnumerable` under the hood.<jupyter_code>seq { for i = 1 to 10 do i }<jupyter_output><empty_output><jupyter_text>The key difference is that a each element of the list is not evaluted until the consumer asks for it. A list and arry on the other hand evaluates all it's elements immediately.This means that you can have infinite sequences<jupyter_code>let batforever = seq { while true do yield "batman forever"  }<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0667754103374452, 'fraction_numerical': 0.014068712406973188, 'mean_word_length': 4.6869565217391305, 'pattern_counts': {'":': 0, '<': 103, '<?xml version=': 0, '>': 108, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '23', 'dir': 'jupyter-structured-clean-dedup', 'id': '334598', 'license': 'MIT', 'n_tokens_mistral': 2848, 'n_tokens_neox': 2659, 'n_words': 1406, 'path': '02-expressions.ipynb', 'repo_name': 'odytrice/fsharp-basics', 'size': '9809'}