Skip to content

Instantly share code, notes, and snippets.

@sam
Last active December 14, 2015 09:50
Show Gist options
  • Save sam/5067898 to your computer and use it in GitHub Desktop.
Save sam/5067898 to your computer and use it in GitHub Desktop.
Pattern Matching examples. Try them out in your REPL!
// One way to think about "match" is as a "map" method for arbitrary objects:
// So I can "map" a number:
10 match { case i => i * 4 }
// Mapping Tuples is especially awesome:
(1, "one") match { case (i,s) => i + 1 -> s"$s!!!" }
// Ok, maybe you're not all that impressed. Now that you know
// you can "map" a Tuple with Pattern Matching, it makes using
// Tuples as return values much more powerful though:
def squareAndSum(values:List[Int]):(List[Int], Int) = {
values.foldLeft((List[Int](), 0)) { case ((l,sum), i) =>
(l ++ List(i * i), sum + i)
}
}
// And not a temporary variable in sight:
squareAndSum(List(1,2,3,4)) match { case (powers, sum) =>
println(s"Sum: $sum\nPowers:")
powers.foreach(println)
}
// This is especially useful with recursive methods like a foldLeft operation
// that needs to return both a list plus an accumulator. Sort of a "foldMap".
// Case classes have "Extractors", which allows us to refer
// to their inner fields in pattern matching:
case class Account(balance:Int)
// And now we can "map" an Account using another account as input without
// having to use a temporary variable for our matched Account:
Account(1000) match { case Account(balance) => Account(balance + 100) }
// Here's how you might achieve the above without pattern-matching:
val bob = Account(1000)
Account(bob.balance + 100)
// Or if there were other fields you needed to preserve as well:
case class Account(balance:Int, term:Int)
val bob = Account(1000, 36)
bob.copy(balance = bob.balance + 100)
// And the same for pattern matching:
Account(1000, 36) match { case a:Account => a.copy(a.balance + 100) }
// Or:
Account(1000, 48) match { case Account(b,t) => Account(b + 100, t) }
// Note because of the very narrow scope, I don't think there's much of
// an argument for "descriptive variable names". Everyone knows what (a,i)
// is when reducing a List[Int]. Everyone knows what T, K or M[_] is when
// dealing with generics. Everyone knows what (i) means in a mapping
// operation. There's conventions here when dealing with a narrow scope.
// It's a one liner. It's obvious. If it gets bigger, fix it.
// Do what feels right. The important thing is that you're not leaking
// this narrow scope so someone else has to guess what Account.b is.
// The context is what sets the tone here. What's good advice in the
// context of your larger program (descriptive variable names) is just
// tedious boiler-plate in your one-liner case expression.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment