Skip to content

Unboxed Forall#1417

Merged
TomasMikula merged 2 commits into
scalaz:series/8.0.xfrom
TomasMikula:unboxed-forall
Sep 4, 2017
Merged

Unboxed Forall#1417
TomasMikula merged 2 commits into
scalaz:series/8.0.xfrom
TomasMikula:unboxed-forall

Conversation

@TomasMikula
Copy link
Copy Markdown
Member

Define Forall[F[_]] as an abstract type, privately implemented as

type Forall[F[_]] = F[Any]

A type alias is provided

type [F[_]] = Forall[F]

Creating instances

Since Forall[F] is represented as F[Any], care needs to be taken so that only truly parametric instances can be created. Two ways to create instances are provided:

  1. From a "prototype", which is a Scalaz7-style universally quantified value:

    def from[F[_]](p: Prototype[F]): Forall[F]
    
    trait Prototype[F[_]] {
      def apply[A]: F[A]
    }

    Prospectively, there could be convenient syntax for creating Prototypes via Syntax for polymorphic values. typelevel/kind-projector#54.

    Note that creation via a prototype requires an allocation of a short-lived object (the prototype), but the resulting Forall[F] value is unboxed. (Perhaps that one allocation could be eliminated by the optimizer?)

  2. Via the same trick (due to @alexknvl) as in Add FunctionH #1416:

    val l1: Forall[List] = Forall.of[List](Nil)
    
    // or
    
    val l2: Forall[List] = Forall.mk[Forall[List]].from(Nil)

    The seemingly longer mk[...].from(...) syntax becomes more succinct in some cases:

    def listSemigroup[A]: Semigroup[List[A]] = ???
    
    type Plus[F[_]] = Forall[λ[A => Semigroup[F[A]]]]
    
    val listPlus: Plus[List] = Forall.of[λ[A => Semigroup[F[A]]]](listSemigroup)
    
    // vs
    
    val listPlus: Plus[List] = Forall.mk[Plus[List]].from(listSemigroup)

Using instances

From user's perspective Forall[F] is completely abstract, but values are enriched with apply[A] method:

class ForallOps[F[_]](val a: Forall[F]) extends AnyVal {
  def apply[A]: F[A] = ???
}

One then uses this method to get an instance specialized for a specific type:

listPlus[Int].append(List(1, 2), List(3, 4)) // List(1, 2, 3, 4)

See also ForallUsage.scala on how Forall can be used to represent NaturalTransformation.

@aloiscochard
Copy link
Copy Markdown

This is beautiful work, I ❤️ it.

What about adding the $ syntax directly in base? seems pretty useful to me.

Should we add this in default Prelude? I think yes.

@TomasMikula
Copy link
Copy Markdown
Member Author

In this PR, ~> is used just as an example. We can consider $ syntax when adding natural transformation. Though there might be confusion about preference, since a $ b $ c in Scala is (a $ b) $ c, whereas in Haskell it is a $ (b $ c). I used $ because Forall already has an apply method.

Yeah, I will add it to Prelude.

@TomasMikula
Copy link
Copy Markdown
Member Author

Added to Prelude. Maybe there's a better organization of the code?

@aloiscochard
Copy link
Copy Markdown

Looks great!

@TomasMikula TomasMikula merged commit 7f3e5d3 into scalaz:series/8.0.x Sep 4, 2017
@TomasMikula TomasMikula deleted the unboxed-forall branch September 4, 2017 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants