定义参数化函数类型

时间:2018-02-15 11:07:53

标签: scala

我想为遵循某些约束的参数化函数定义一个新类型。类似的东西:

import scala.util.Try
type Bound = Any

trait T1 {
  def apply[A <: Bound](a: A): Try[A]
}

这是有效的,但定义类型T1的函数的唯一方法是例如。

val t1: T1 = new T1 {
    override def apply[A](a: A): Try[A] = Try(a)
}

这有点麻烦。编写类似内容的更合适的方法是使用函数文字。

有办法吗?

请记住定义类似的类型:

trait T2[A <: Bound] extends (A => Try[A])

将无效,因为该类型的每个实例都必须定义类型参数,牺牲已定义实例的genericness

val t: T2[Int] = (a: Int) => Success(a)

2 个答案:

答案 0 :(得分:1)

(未经测试,只是一个可能有用的想法)

我不清楚Scala中的简明语法。

但是,如果您愿意稍微概括T1,那么有些插件会尝试解决您问题的稍微更一般的版本。

你要问的是:&#34;是否有自然变换的内联语法&#34;:

trait T1[F[_], G[_]] {
  def apply[A <: UpperBound](x: F[A]): G[A]
}

在您的情况下,FIdGTry,此外,您对A有约束。这种模式相当常见,因此例如here建议您使用非/ kind-projector编译器插件来实现这种情况。这将允许你写这个:

val t1 = λ[T1[Id, Try]](bodyOfTheApplyMethod)

documentation of non/kind-projector compiler plugin中,列出了几项要求可行的要求。特别是,T1确实需要由两个类型构造函数FG进行参数化。而且,我不确定在重写期间插入正确位置的类型是否足够聪明。

话虽如此,我只是和

一起去
val t1 = new T1 { 
  def apply[X <: Bound](x: X): Try[X] = body 
}

我认为以最佳方式解决您的具体问题,您必须修改非/ kind-projector插件。或者等待dotty的未来版本。或者切换到具有依赖类型的语言,其中类型参数和普通参数之间没有太大区别。

或者只是按原样接受并使用new ... { def ... } - 语法。

答案 1 :(得分:0)

这应该可以使用配套对象:

import scala.util.{Success, Try}
type Bound = Any

trait T1[A <: Bound] {
  def apply(a: A): Try[A]
}

object T1 {
  def apply[A <: Bound](f: A => Try[A]) = {
    new T1[A] {
      override def apply(a: A): Try[A] = f(a)
    }
  }
}

val t1 = T1( (a: Int) => Success(a) )

但是我担心它与您特别不想使用的trait T2[A <: Bound]解决方案完全相同 - 以这种方式创建的函数不再是通用的。

我担心使用apply的通用T1成员的方法注定要失败,因为使用该接口,您承诺提供通用功能。没有办法用文字来满足这个承诺,Scala 2.12 SAM不会改变它。