Skip to content

Instantly share code, notes, and snippets.

@manjuraj
Last active September 15, 2017 19:43
Show Gist options
  • Save manjuraj/b56e3377d562fdf0d283 to your computer and use it in GitHub Desktop.
Save manjuraj/b56e3377d562fdf0d283 to your computer and use it in GitHub Desktop.

Revisions

  1. manjuraj revised this gist Mar 9, 2015. 1 changed file with 20 additions and 2 deletions.
    22 changes: 20 additions & 2 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@
    // - https://gist.github.com/retronym/229163
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    // - http://www.scala-lang.org/old/node/4041.html
    //
    // - https://groups.google.com/forum/#!searchin/scala-user/generic$20type$20constraint/scala-user/mgx9-TUapQo/tiN6x818dKsJ

    //
    // Scala 2.8 introduces generalized type constraints which 3 variants:
    @@ -188,4 +188,22 @@ scala> firstLast(List(1,2,3))
    def firstLast[A, C](it: C)(implicit ev: C <:< Iterable[A]) = (it.head, it.tail)

    scala> firstLast(List(1,2,3))
    res2: (Int, Iterable[Int]) = (1,List(2, 3))
    res2: (Int, Iterable[Int]) = (1,List(2, 3))

    // Alternatively, you can get specific about types by using
    // higher kinded types

    scala> import scala.language.higherKinds

    scala> def firstLast[A, C[B] <: Iterable[B]](it: C[A]) = (it.head, it.tail)
    firstLast: [A, C[B] <: Iterable[B]](it: C[A])(A, Iterable[A])

    scala> firstLast(List(1,2,3))
    res1: (Int, Iterable[Int]) = (1,List(2, 3))

    // This however doesn't give what I intended
    scala> def firstLast[T, C[_] <: Iterable[_]](it: C[T]) = (it.head, it.tail)
    firstLast: [T, C[_] <: Iterable[_]](it: C[T])(Any, Repr)

    scala> firstLast(List(1,2,3))
    res0: (Any, Repr) = (1,List(2, 3))
  2. manjuraj revised this gist Feb 27, 2015. 1 changed file with 33 additions and 0 deletions.
    33 changes: 33 additions & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -5,6 +5,7 @@
    // - https://gist.github.com/retronym/229163
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    // - http://www.scala-lang.org/old/node/4041.html
    //

    //
    // Scala 2.8 introduces generalized type constraints which 3 variants:
    @@ -156,3 +157,35 @@ def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = {
    b.result
    }

    //
    // Example that illustrates how type constraints can be used to supply
    // method to a generic class that can only be used under certain
    // conditions
    //
    case class Pair[T](first: T, second: T) {
    def smaller(implicit ev: T <:< Ordered[T]): T = {
    if (first < second) first else second
    }
    }

    //
    // Use type constraint when the type inteference cannot figure out the
    // types. Here the type inferencer attempts to determinte the types
    // A and C in a single step. Help it along, by first matching on type
    // C and then on A
    //
    def firstLast[A, C <: Iterable[A]](it: C) = (it.head, it.tail)

    scala> firstLast(List(1,2,3))
    <console>:9: error: inferred type arguments [Nothing,List[Int]] do not conform to method firstLast's type parameter bounds [A,C <: Iterable[A]]
    firstLast(List(1,2,3))
    ^
    <console>:9: error: type mismatch;
    found : List[Int]
    required: C
    firstLast(List(1,2,3))
    ^
    def firstLast[A, C](it: C)(implicit ev: C <:< Iterable[A]) = (it.head, it.tail)

    scala> firstLast(List(1,2,3))
    res2: (Int, Iterable[Int]) = (1,List(2, 3))
  3. manjuraj revised this gist Feb 26, 2015. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -10,9 +10,13 @@
    // Scala 2.8 introduces generalized type constraints which 3 variants:
    //
    // - A =:= B means A must be exactly B
    // - A <:< B means A must be a subtype of B, i.e. A must conform to B (analogous to the simple type constraint <:)
    // - A <%< B means A must be viewable as B, possibly via implicit conversion (analogous to the simple type constraint <%)
    //
    // (equalTo)
    // - A <:< B means A must be a subtype of B, i.e. A must conform to B
    // (analogous to the simple type constraint <:)
    // (conformsTo)
    // - A <%< B means A must be viewable as B, possibly via implicit conversion
    // (analogous to the simple type constraint <%)
    // (visibleAs)

    //
    // Unlike <: or >:, the generalized type constraints are not operators. They
  4. manjuraj revised this gist Feb 26, 2015. 1 changed file with 12 additions and 0 deletions.
    12 changes: 12 additions & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -140,3 +140,15 @@ def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C,
    case Left(a) => a
    case Right(b) => Right(b)
    }

    //
    // toMap from TraversableOnce
    // - toMap only works if Traversable contains 2-tuples
    //
    def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = {
    val b = immutable.Map.newBuilder[T, U]
    for (x <- self)
    b += x
    b.result
    }

  5. manjuraj revised this gist Feb 26, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    //
    // References
    // - http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
    // - http://stackoverflow.com/questions/2603003/operator-in-scala
    // - https://gist.github.com/retronym/229163
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    // - http://www.scala-lang.org/old/node/4041.html
  6. manjuraj revised this gist Feb 26, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // - http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
    // - https://gist.github.com/retronym/229163
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    //
    // - http://www.scala-lang.org/old/node/4041.html

    //
    // Scala 2.8 introduces generalized type constraints which 3 variants:
  7. manjuraj revised this gist Feb 26, 2015. 1 changed file with 61 additions and 10 deletions.
    71 changes: 61 additions & 10 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -69,16 +69,17 @@ res1: Int = 4
    // orNull from Option.scala
    //

    /** Returns the option's value if it is nonempty,
    * or `null` if it is empty.
    * Although the use of null is discouraged, code written to use
    * $option must often interface with code that expects and returns nulls.
    * @example {{{
    * val initalText: Option[String] = getInitialText
    * val textField = new JComponent(initalText.orNull,20)
    * }}}
    */
    @inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null
    /**
    * Returns the option's value if it is nonempty,
    * or `null` if it is empty.
    * Although the use of null is discouraged, code written to use
    * $option must often interface with code that expects and returns nulls.
    * @example {{{
    * val initalText: Option[String] = getInitialText
    * val textField = new JComponent(initalText.orNull,20)
    * }}}
    */
    @inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null

    scala> Some("string").orNull
    res3: String = string
    @@ -87,4 +88,54 @@ scala> Some(1231).orNull
    <console>:8: error: Cannot prove that Null <:< Int.
    Some(1231).orNull

    //
    // joinsRight and joinsLeft from Either.scala
    //

    /**
    * Joins an `Either` through `Right`.
    *
    * This method requires that the right side of this Either is itself an
    * Either type. That is, this must be some type like: {{{
    * Either[A, Either[A, C]]
    * }}} (which respects the type parameter bounds, shown below.)
    *
    * If this instance is a Right[Either[A, C]] then the contained Either[A, C]
    * will be returned, otherwise this value will be returned unmodified.
    *
    * @example {{{
    * Right[String, Either[String, Int]](Right(12)).joinRight // Result: Right(12)
    * Right[String, Either[String, Int]](Left("flower")).joinRight // Result: Left("flower")
    * Left[String, Either[String, Int]]("flower").joinRight // Result: Left("flower")
    * }}}
    *
    * This method, and `joinLeft`, are analogous to `Option#flatten`
    */
    def joinRight[A1 >: A, B1 >: B, C](implicit ev: B1 <:< Either[A1, C]): Either[A1, C] = this match {
    case Left(a) => Left(a)
    case Right(b) => b
    }

    /**
    * Joins an `Either` through `Left`.
    *
    * This method requires that the left side of this Either is itself an
    * Either type. That is, this must be some type like: {{{
    * Either[Either[C, B], B]
    * }}} (which respects the type parameter bounds, shown below.)
    *
    * If this instance is a Left[Either[C, B]] then the contained Either[C, B]
    * will be returned, otherwise this value will be returned unmodified.
    *
    * {{{
    * Left[Either[Int, String], String](Right("flower")).joinLeft // Result: Right("flower")
    * Left[Either[Int, String], String](Left(12)).joinLeft // Result: Left(12)
    * Right[Either[Int, String], String]("daisy").joinLeft // Result: Right("daisy")
    * }}}
    *
    * This method, and `joinRight`, are analogous to `Option#flatten`
    */
    def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1] = this match {
    case Left(a) => a
    case Right(b) => Right(b)
    }
  8. manjuraj revised this gist Feb 26, 2015. 1 changed file with 24 additions and 2 deletions.
    26 changes: 24 additions & 2 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,8 @@
    //
    // References
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    // - http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
    // - https://gist.github.com/retronym/229163
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    //

    //
    @@ -48,7 +48,6 @@ object <%< {
    }
    }


    //
    // Examples
    //
    @@ -66,3 +65,26 @@ scala> Foo(1234).length
    scala> Foo("asdf").length
    res1: Int = 4

    //
    // orNull from Option.scala
    //

    /** Returns the option's value if it is nonempty,
    * or `null` if it is empty.
    * Although the use of null is discouraged, code written to use
    * $option must often interface with code that expects and returns nulls.
    * @example {{{
    * val initalText: Option[String] = getInitialText
    * val textField = new JComponent(initalText.orNull,20)
    * }}}
    */
    @inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null

    scala> Some("string").orNull
    res3: String = string

    scala> Some(1231).orNull
    <console>:8: error: Cannot prove that Null <:< Int.
    Some(1231).orNull


  9. manjuraj revised this gist Feb 26, 2015. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,7 @@
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    // - http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
    // - https://gist.github.com/retronym/229163
    //

    //
    // Scala 2.8 introduces generalized type constraints which 3 variants:
  10. manjuraj created this gist Feb 26, 2015.
    67 changes: 67 additions & 0 deletions gistfile1.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    //
    // References
    // - http://debasishg.blogspot.com/2010/08/using-generalized-type-constraints-how.html#sthash.GKfUGq9p.dpuf
    // - http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
    // - https://gist.github.com/retronym/229163

    //
    // Scala 2.8 introduces generalized type constraints which 3 variants:
    //
    // - A =:= B means A must be exactly B
    // - A <:< B means A must be a subtype of B, i.e. A must conform to B (analogous to the simple type constraint <:)
    // - A <%< B means A must be viewable as B, possibly via implicit conversion (analogous to the simple type constraint <%)
    //

    //
    // Unlike <: or >:, the generalized type constraints are not operators. They
    // are classes, and instances of which are implicitly provided by the compiler
    // itself to enforce conformance to the type constraints.
    //

    //
    // Type Constraints from Predef.scala:
    // used, for example, in the encoding of generalized constraints
    // we need a new type constructor `<:<` and evidence `conforms`, as
    // reusing `Function2` and `identity` leads to ambiguities (any2stringadd is inferred)
    // to constrain any abstract type T that's in scope in a method's argument list (not just the method's own type parameters)
    // simply add an implicit argument of type `T <:< U`, where U is the required upper bound (for lower-bounds, use: `U <: T`)
    // in part contributed by Jason Zaugg
    //
    sealed abstract class <:<[-From, +To] extends (From => To)
    implicit def conforms[A]: A <:< A = new (A <:< A) {
    def apply(x: A) = x
    }
    // not in the <:< companion object because it is also intended to subsume identity (which is no longer implicit)

    sealed abstract class =:=[From, To] extends (From => To)
    object =:= {
    implicit def tpEquals[A]: A =:= A = new (A =:= A) {
    def apply(x: A) = x
    }
    }

    sealed abstract class <%<[-From, +To] extends (From => To)
    object <%< {
    implicit def conformsOrViewsAs[A <% B, B]: A <%< B = new (A <%< B) {
    def apply(x: A) = x
    }
    }


    //
    // Examples
    //

    case class Foo[A](a: A) { // 'A' can be substituted with any type
    // getStringLength can only be used if this is a Foo[String]
    def length(implicit evidence: A =:= String) = a.length
    }

    scala> Foo(1234).length
    <console>:10: error: Cannot prove that Int =:= String.
    Foo(1234).length
    ^

    scala> Foo("asdf").length
    res1: Int = 4