# Functional Programming, Simplified
# Partially-Applied Functions
Scala code won't compile if you don't supply the later parameter groups, i.e.
def plus(a: Int)(b: Int): Int = a + b
plus(2) // won't compile
We have to explicitly use _
if we want it to return the partially applied function:
plus(2)(_) // compiles to a curried function
The advantage is you don't have to partially apply the functions in the order in which they were defined, e.g. you can omit the middle parameter with _
and it compiles fine:
def wrap(prefix: String)(html: String)(suffix: String): String = prefix + html + suffix
val wrapWithDiv = wrap("<div>")(_: String)("</div>")
wrapWithDiv("hi!") // <div>hi!</div>
# Opening Curly Brace
One weird scala structure (1):
val x = FOO { (s: State) =>
// more code
}
Or just (2):
val x = FOO {
// more code
}
What FOO is depends on whether it is (1) or (2):
- FOO is either an anonymous class or a function that takes a by-name parameter.
- FOO is either a class that takes a function parameter or a function that takes a by-name parameter.
# Anonymous class
val mary = new Person {
val name = "mary"
val age = 25
}
This code creates a new Person instance using Scala's anonymous class syntax.
- We know it's not a
case class
because acase class
requires at least one constructor parameter and does not allow thenew
keyword.
# By-name parameter
def timer[A](blockOfCode: => A) = ???
val time = timer {
// some long code
}
Since blockOfCode
is received by-name, we can use the timer
function with the open curly brackets.
# IO Monad
The IO monad or IO container wraps impure IO functions. Instead of running the impure functions right away, IO allows you to provide a description of how you would like to deal with the result of the impure function and defers the actual action to some time later.
e.g. This piece of code prints "Hello, world"
to the console right away:
object HelloWorld extends App {
val result = println("Hello, world")
}
Whereas this does not print anything:
object AlmostHelloWorld extends App {
val result = IO { println("Hello, world") }
}
This allows us to pass the IO around, use it in for
comprehensions, map
over it, flatMap
over it, etc.
To "run" the IO, we call its unsafePerformIO
function:
object HelloWorld extends App {
val result = IO { println("Hello, world") }
result.unsafePerformIO()
}