Let's consider some value holder. For example, Try monad. For simplicity, Let's assume it only works with Int32
.
record Success, value : Int32
record Failure, value : Exception
# some try object
try : Success | Failure = Success(1)
It usually looks like this by using crystal's case statement.
# Extract it.
case try
when Success
v = try.value
puts "Got #{v}"
when Failure
e = try.value
puts "Oops, #{e}"
end
Generally, we can write intuitively in languages with extractor, such as Scala, Rust, and more recently, Ruby.
try match {
case Success(v) => printf("Got %s\n", v)
case Failure(e) => ...
match try {
Success(v) => println!("Got {:?}", v),
Failure(e) => ...
case try
in Success(value: v); puts "Got #{v}"
in Failure(value: e); ...
But we Crystal have powerful macros. Let's define it by myself!
module Try
macro match(try)
case {{try}}
{{yield}} # To be precise, parse 'when' here and extract the value
end
end
end
Try.match(try) {
when Success(v) then puts "Got #{v}"
}
How elegant! But we will get...
Error: expecting token '}', not 'when'
This style is called Partial Function in Scala. That is first class object and it can be applied to case
sentences.
val pf:PartialFunction[Try,Int32] = {
case Success(v) => printf("Got %s\n", v)
case Failure(e) => ...
}
my_try_match(pf) // works
Thus, my wishes are.
- Crystal will support Extractor. (best)
- Crystal will support Partial Function for AST. (second best)
Since I had no choice, I now use the local variable
TypeDeclaration
😃https://github.com/maiha/try.cr/blob/master/spec/match_spec.cr#L66-L71