Skip to content

Instantly share code, notes, and snippets.

@rahulkumar-aws
Created November 10, 2018 13:51
Show Gist options
  • Select an option

  • Save rahulkumar-aws/266c0cbfc0bb72951aab99143f9c15a5 to your computer and use it in GitHub Desktop.

Select an option

Save rahulkumar-aws/266c0cbfc0bb72951aab99143f9c15a5 to your computer and use it in GitHub Desktop.

Revisions

  1. rahulkumar-aws created this gist Nov 10, 2018.
    335 changes: 335 additions & 0 deletions let-me-count-the-ways-scala.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,335 @@
    ```scala
    object Functions extends App {

    //
    // Function Calls
    //

    // basic function call with a single param
    println("foo")


    // function call with a block param
    println { "foo" }


    // function call with a more complex block param
    println {
    val f = "f"
    f + "oo"
    }


    // fully qualified function call
    Predef.println("foo")


    // infix function call
    Predef println "foo"


    // named param function call
    println(x = "foo")


    // optional parens for no-param function
    // Note: println is overloaded taking either no params or a single param
    println()
    println


    // identifier
    `println`("foo")


    //
    // Function Definitions
    //

    // no params for a function def
    def noParams = scala.util.Random.alphanumeric.take(8).mkString

    println(noParams)


    // parens for a no-param function def
    def noParamsWithParens() = scala.util.Random.alphanumeric.take(8).mkString

    println(noParamsWithParens)


    // def with a return type
    def noParamsWithParensAndReturnType(): String = scala.util.Random.alphanumeric.take(8).mkString

    println(noParamsWithParensAndReturnType)


    // single param def
    def aSingleParamDef(s: String) = s.toUpperCase

    println(aSingleParamDef("foo"))


    // function body in a block
    def aSingleParamDefBlock(s: String) = {
    s.toUpperCase
    }

    println(aSingleParamDefBlock("foo"))


    // function body in parens
    def aSingleParamDefParens(s: String) = (
    s.toUpperCase
    )

    println(aSingleParamDefParens("foo"))


    // single param and return type
    def aSingleParamDefWithReturnType(s: String): String = s.toUpperCase

    println(aSingleParamDefWithReturnType("foo"))


    // function val
    val aSingleParamFunctionVal = (s: String) => s.toUpperCase

    println(aSingleParamFunctionVal("foo"))


    // function val with body in a block
    val aSingleParamFunctionValBlock = {
    (s: String) => s.toUpperCase
    }

    println(aSingleParamFunctionValBlock("foo"))


    // two param def
    def twoParamDef(s: String, i: Int): String = s.take(i)

    println(twoParamDef("hello", 2))


    // multiple parameter sets
    def twoParamSetsDef(s: String)(i: Int): String = s.take(i)

    println(twoParamSetsDef("hello")(2))


    // partially applied function
    val partiallyAppliedFunction = twoParamSetsDef("hello")(_)

    println(partiallyAppliedFunction(3))


    // partially applied function where the second parameter is applied
    val anotherPartiallyAppliedFunction: (String => String) = twoParamSetsDef(_)(1)

    println(anotherPartiallyAppliedFunction("foo"))


    // polymorphic type parameter for a def
    def typeParamDef[T](o: Option[T]): Boolean = o.isDefined

    println(typeParamDef(Some("foo")))
    println(typeParamDef[String](Some("foo")))


    // create an instance of a single parameter function
    val aFunction1 = new Function1[String, String] {
    override def apply(s: String): String = s.toUpperCase
    }

    println(aFunction1("foo"))


    // create an instance of a single parameter function but use parens after the type
    val aFunction1WithParens = new Function1[String, String]() {
    override def apply(s: String): String = s.toUpperCase
    }

    println(aFunction1WithParens("foo"))


    // shorthand for creating a new single parameter function
    val anotherFunction1 = new (String => String) {
    override def apply(s: String): String = s.toUpperCase
    }

    println(anotherFunction1("foo"))


    // single input parameters can optionally be wrapped in parens
    val yetAnotherFunction1 = new ((String) => String) {
    override def apply(s: String): String = s.toUpperCase
    }

    println(yetAnotherFunction1("foo"))


    // shorthand for a single parameter function
    val andAnotherFunction1 = (s: String) => s.toUpperCase

    println(andAnotherFunction1("foo"))


    // shorthand for a partial function val
    val aPartialFunction: PartialFunction[String, String] = {
    case s: String => s.toUpperCase
    }

    println(aPartialFunction("foo"))


    // shorthand for a partial function def
    def aPartialFunctionDef: PartialFunction[String, String] = {
    case s: String => s.toUpperCase
    }

    println(aPartialFunctionDef("foo"))


    // create a new instance of a partial function
    val anotherPartialFunction = new PartialFunction[String, String] {
    override def isDefinedAt(s: String): Boolean = true
    override def apply(s: String): String = s.toUpperCase
    }

    println(anotherPartialFunction("foo"))


    // an operator
    def &%->(): String = "foo"

    println(&%->())


    // right-associative by putting a colon on the right side of the method name
    class Foo {
    def #:(s: String): String = s.reverse
    }

    val foo = new Foo

    // normal operator call
    println(foo.#:("asdf"))

    // reverse infix call
    println("asdf" #: foo)


    // no equals necessary for functions that return Unit
    def returnsUnit() {
    println("bad form")
    }

    returnsUnit()


    // call by name params are evaluated each time the are accessed
    def callByName(byName: => String, byValue: String): Unit = {
    println(byName, byValue)
    println(byName, byValue)
    }

    callByName(scala.util.Random.alphanumeric.take(8).mkString, scala.util.Random.alphanumeric.take(8).mkString)


    // default values
    def defaultValues(s: String = "asdf") = s.toUpperCase

    //
    println(defaultValues("foo"))

    // the parens are required
    println(defaultValues())


    //
    // Higher-order Functions
    //

    // a function that takes a string and returns it in upper case
    def toUpperCase(s: String): String = s.toUpperCase

    // a higher-order function that takes a function, and calls it with the string "foo"
    def aHigherOrderFunction(f: String => String): String = f("foo")

    println(aHigherOrderFunction(toUpperCase))


    // single input type parameters can optionally be wrapped with parens
    def anotherHigherOrderFunction(f: (String) => String): String = f("foo")

    println(anotherHigherOrderFunction(toUpperCase))


    // multiple input type parameters must be wrapped with parens
    def multipleInputParamHigherOrderFunction(f: (String, Int) => String): String = f("foo", 1)


    // no input type parameters
    // note: the call to f must use parens in this context
    def noInputParamHigherOrderFunction(f: () => String): String = f()


    // a higher-order function that returns a function
    def returnsAHigherOrderFunction: (String => String) = toUpperCase

    println(returnsAHigherOrderFunction("foo"))


    // anonymous function where s is the string input parameter
    println {
    anotherHigherOrderFunction { s =>
    s.toUpperCase
    }
    }


    // anonymous function with input type specified
    println {
    anotherHigherOrderFunction { s: String =>
    s.toUpperCase
    }
    }


    // anonymous function with partial function from a case statement
    println {
    anotherHigherOrderFunction { case s: String =>
    s.toUpperCase
    }
    }


    // anonymous function with multiple params
    println {
    multipleInputParamHigherOrderFunction { (s, i) =>
    s.take(i)
    }
    }


    // anonymous function with multiple params via a case statement
    println {
    multipleInputParamHigherOrderFunction { case (s: String, i: Int) =>
    s.take(i)
    }
    }


    // shorthand anonymous function
    println(anotherHigherOrderFunction(_.toUpperCase))


    // polymorphic type param with a higher-order function
    def aTypeParamedHigherOrderFunction[T](f: String => T) = f("foo")

    println(aTypeParamedHigherOrderFunction(_.length))
    println(aTypeParamedHigherOrderFunction[Int](_.length))

    }
    ```