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…