Student: Long time no see. I have time to chat again today

Fang: Well, TODAY I want to talk with you about Maybe and pattern matching

Directly to the TypeScript code:

const addMark = (whatever? :string) = > whatever + '! '
addMark('Frank') 
/ / output Frank!
addMark() 
/ / output undefined!
Copy the code

Final output of undefined! It’s not the output that we want. How do you usually solve this problem?

Student: “empty”

Fang: Yes, the code looks something like this:

const addMark = (whatever? :string) = > {
  if(whatever ! = =undefined) {return whatever + '! '
  } else {
    return '! '
  }
}
 
addMark() 
/ / output!
Copy the code

Let me ask you, what’s the “whatever” type these days?

Student: String

Is undefined a string?

Student: oh, I see what you mean, whatever is of type string | is undefined

Fong: Now let me give you another idea. We can use Maybe

for whatever type

Student: No, how to write the code

Party: Code:

type Just<X> = { _type: 'Just'.value: X }
type Nothing = { _type: 'Nothing' }
type Maybe<X> = Nothing | Just<X>
const createMaybe = 
  <T>(value:T): Maybe<T> => 
    value === undefined ? {_type: 'Nothing'}, {_type: 'Just', value}


const addMark = (whatever: Maybe<string>) = > {
  if(whatever._type === 'Just') {return whatever.value + '! '
  } else if(whatever.type === 'Nothing') {
    return '! '}}const readStringFromFile = () = >{
  return createMaybe<string> ('hi')}const fileContent = readStringFromFile()

console.log(addMark(fileContent))
Copy the code

Student: No undefined and null, but you still have to judge whatever._type is ‘Just’ or ‘Nothing’, right?

Fang: Yes, this is due to the limited expression ability of JS. If written in Haskell, with pattern matching, the code is quite concise:

-- [Char] is a String
readStringFromFile: :Char] - >Maybe [Char] 
readStringFromFile path = Just "hi" 
-- file may not exist, return empty, so I'm going to say "hi"


addMark: :Maybe [Char] - > [Char]
addMark (Just str) = str ++ "!"
addMark Nothing = "!"


main: :IO(a)main = do 
  print $ addMark $ readStringFromFile "./1.txt"

- output "hi!"
Copy the code

You see, there’s no null/undefined, and there’s no if else.

Student: What is pattern matching?

Fong: Actually, it’s very simple. We just look at addMark

addMark: :Maybe [Char] - > [Char]
AddMark: Maybe [Char]
There are only two cases: Just [Char] and Nothing

Just [Char] adds an exclamation point to STR
addMark (Just str) = str ++ "!"
Nothing returns an exclamation point
addMark Nothing = "!"
Copy the code

Student: Looks like switch… Case is similar

Fang: No, switch… Case is a comparison of concrete “values,” while pattern matching is a “formal” match, which is more abstract.

Let’s practice pattern matching. Here’s Fibonacci:

fib: :Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib (n- 1) + fib (n2 -) 
This version is extremely slow and needs to be optimized
Copy the code

This is quicksort:

qs: :Int] - > [Int]
qs [] = []
qs (first:rest) =
  qs (filter (<= first) rest) 
    ++ [first] 
    ++ qs (filter (> first) rest)
Copy the code

And you can obviously see that with pattern matching, there’s almost no need to write if else.

Student: Pretty convenient. Why doesn’t JS introduce pattern matching?

JS also wants to introduce it, but it is still under discussion. Here is a proposal, the specific code looks like this:

const res = await fetch(jsonService)
case (res) {
  when {status: 200.headers: {'Content-Length': s}} ->
    console.log(`size is ${s}`),
  when {status: 404} - >console.log('JSON not found'),
  when {status} if (status >= 400) - > {throw new RequestError(res)
  },
}
Copy the code

case … when … Such code is pattern matching.

Student: I know about pattern matching, it’s the advanced version of Switch… The case. But Maybe I still don’t understand

In Haskell, Maybe is defined as

data Maybe a = Nothing | Just a -- where a can be Int / [Char], etc
Copy the code

For reference, you can look at the definition of Bool in Haskell

data Bool = True | False
Copy the code

You don’t care what the keyword data means, you just plug it in, right

Maybe Int = Nothing | Just Int
Maybe [Char] = Nothing | Maybe [Char]
Copy the code

Student: So what is Just in Just “hi”? Function? Or class?

Just, like True or False, is a special value. Just “hi” is a whole, it does not equal “hi”, it is used for pattern matching.

Student: How do you get “hi” from Just “hi”?

You can write a getValue

getValue: :Maybe [Char] - > [Char]
getValue (Just x) = x
getValue Nothing = error "Unreadable value"

main = do 
  print $ getValue $ Just "hi"  - output "hi"
Copy the code

But this is very much not recommended.

Student: What do you recommend?

Fang: I recommend “don’t take the value out of Maybe yet”, just use pattern matching when you really need the value:

main = do 
  let maybe = getContentFromFile "./1.txt"
  case maybe of
    Just x -> print $ "result: " ++ x
    Nothing -> print $ "we got nothing"
Copy the code

Student: I don’t know. Wouldn’t it be easier if I took it out first and got a string?

This is true in JS, but Haskell is a language that supports lazy evaluation. It’s hard to explain why JS doesn’t support lazy evaluation. Let me give you another example. If getContentFromFile is an asynchronous operation, how do you get the value? You can’t get the value, but you can write the next operation first.

Student: You remind me of Promise

Fang: Yes, the promise value may come back in 3 seconds. You can’t wait 3 seconds for it to come back.

let promise = readFilePromise("./1.txt")
promise.then(
  x= > console.log("result: " + x),
  error= > console.log("we go nothing"))Copy the code

Do you notice any similarities between the two code mysteries above?

Student: How do I feel that Maybe is the Promise of synchronization? Maybe

means there could be string or empty, and Promise

means there could be User or empty.

Fang: It’s kind of interesting. we’ll see what they have in common later.

Student: With JS empty, is there no need to have Maybe type?

Fang: Yes, just like we talked about “closures and objects” before, they are the same path, the same language

  • Or like JS, whatever the type of string | undefined, you write whatever. The split (‘) is not an error, run
  • Or like TS, whatever the type of string | undefined, but whatever. The split (‘ ‘) error, request you to empty first
  • Or like Haskell, whatever the type is Maybe (Char), that is Just [chars] | Nothing, you can’t call directly through whatever string API, unless you use pattern matching to get the string value

All three schemes can achieve the same goal, in which THE JS approach is the most insecure, but the novice preferred. Both TS and Haskell are safe, and veterans like them.

Student: It turns out that learning programming requires mastering so many programming languages

Fang: That’s right!

To be continued…