我正在尝试将(非常有趣的)论文Build systems a la carte中的代码从Haskell转换为Scala,以便进行自学。 我远不是Scala或Haskell的专家,所以在尝试编写等效的(第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)
在阅读帖子forall in Scala之后,我尝试了翻译由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]]
}
但我收到此错误消息:
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] {
我没有对MyTask类犯任何错误。我想这是因为Scalaz Applicative将类型构造函数作为参数(据我了解),而MyApplicative是简单类型。
我迷失了Scala类型系统的复杂性,因此,如果有人可以帮助我找到解决方案,我将不胜感激。
谢谢。
答案 0 :(得分:1)
我们从Haskell代码开始。
newtype Task c k v = Task { run :: forall f. c f => (k -> f v) -> f v }
在Scala中,我们必须显式注释类型参数的类型,因此我们向ghci
询问构造函数Task
的类型:
> :t Task
Task :: (forall (f :: * -> *). c f => (k -> f v) -> f v) -> Task c k v
我们了解到f
的类型为* -> *
,因此我们必须在Scala中使用F[_]
进行指定。
然后我们向ghci
询问类型Task
的类型:
> :k Task
Task :: ((* -> *) -> Constraint) -> * -> * -> *
我们了解到k
和v
都具有种类*
,而c
也具有种类((* -> *) -> Constraint)
。在Scala中,我们不需要为类型*
做任何特殊的事情,但是对于((* -> *) -> Constraint
,我们必须做两件事:
*
代替Constraint
,因为约束已在Scala中编码为正确的类型((* -> *) -> *)
来指定结果类型C[_[_]]
。总体而言,我们得到:
trait Task[C[_[_]], K, V] {
def run[F[_]: C](f: K => F[V]): F[V]
}
答案 1 :(得分:0)
问题在于,Applicative是一个类型类,它将更高种类的类型作为参数Applicative[F[_]]
。任务类期望C[_]
。