0

I am trying to translate the code in the (very interesting) paper Build systems a la carte from Haskell to Scala, for self-study. I am far from being an expert in Scala or Haskell, so I got stuck when trying to write an equivalent of (page 7):

newtype Task c k v = Task { run :: forall f. c f => (k -> f v) -> f v }
type Tasks c k v = k -> Maybe (Task c k v)

After reading the post forall in Scala, I made a tentative to translate the type constraint specified by the forall:

import scalaz.Applicative
import scala.language.higherKinds

trait MyApplicative[_] {}

trait SuchThat[F[_], G[_]] {
  def apply[A:G]: F[A]
}

trait Task[C[_], K, V] {
  type F[X] = ({type f[_]})#f SuchThat C

  var runInt: (K => F[V]) => F[V] = null

  def run = {runInt}

  def apply(r: (K => F[V]) => F[V] ) = {
    runInt = r
  }
}

class ApplicativeTask[K, V] extends Task[Applicative, K, V] {}

class MyTask[K,V] extends Task[MyApplicative, K, V] {}

object TasksObj {
  type Tasks[C[_], K, V] = K => Option[Task[C, K, V]]
}

but I got this error message:

Error: kinds of the type arguments (scalaz.Applicative,K,V) do not conform to the expected kinds of the type parameters (type C,type K,type V) in trait Task.
scalaz.Applicative's type parameters do not match type C's expected parameters:
type F has one type parameter, but type _ has none
class ApplicativeTask[K, V] extends Task[Applicative, K, V] {

I got no errors for class MyTask, instead. I suppose it's because Scalaz Applicative takes a type constructor as parameter (as far as I understand), and MyApplicative a simple type.

I lost myself in the intricacies of Scala type system, so I would appreciate if someone could help me find a solution.

Thanks in advance.

2 Answers2

1

We start with the Haskell code.

newtype Task c k v = Task { run :: forall f. c f => (k -> f v) -> f v }

In Scala, we have to explicitly annotate the kind of type parameters, so we ask ghci about the type of the constructor Task:

> :t Task
Task :: (forall (f :: * -> *). c f => (k -> f v) -> f v) -> Task c k v

We learn that f has kind * -> *, so we have to specify it by using F[_] in Scala.

Then we ask ghci for the kind of the type Task:

> :k Task
Task :: ((* -> *) -> Constraint) -> * -> * -> *

We learn that k and v both have kind * and that c has kind ((* -> *) -> Constraint). In Scala, we don't need to do anything special for kind *, but for ((* -> *) -> Constraint, we have to do two things:

  • We use * instead of Constraint since constraints are encoded as proper types in Scala
  • We have to specify the resulting kind ((* -> *) -> *) by using C[_[_]] in Scala.

Overall, we get:

trait Task[C[_[_]], K, V] {
  def run[F[_]: C](f: K => F[V]): F[V]
}
Toxaris
  • 7,156
  • 1
  • 21
  • 37
0

The problem is that Applicative is a typeclass which takes higher kinded type as a parameter Applicative[F[_]]. And the task class expects C[_].

Okrm
  • 51
  • 5