【发布时间】:2017-11-09 23:09:11
【问题描述】:
我想知道是否有办法修补 Scala 处理 Function1 和 Function2..N 中明显的不一致。
对于Function1,比如Int => String,参数列表 (Int) 与 Int 不同(即使两者是同构的),但编译器会将输入推断为裸Int(参见下面的代码)。
对于Function2..N,说
val f: (String, Int) => String = ???
编译器不会为输入参数列表推断任何类型。特别是,没有 ParameterList[String, Int] 即使它与 (String, Int) 的元组和任何其他您喜欢围绕 Strings 和 Int 的包装器同构。
我的第一个问题是,是否有这样的原因(或者这是否存在于 scala 待办事项列表中)?即为什么可以将 Function1 解构为输入和输出类型,但不能将 Function2 解构,有人想解决这个问题吗?
是否有任何变通方法。具体来说,在下面的代码中,有没有办法让 invoke2 工作?
package net.jtownson.swakka
import org.scalatest.FlatSpec
import org.scalatest.Matchers._
import shapeless.ops.function._
import shapeless.{HList, HNil, _}
class TypeclassOfFunctionTypeSpec extends FlatSpec {
// Here, we know the return type of F is constrained to be O
// (because that's how the shapeless FnToProduct typeclass works)
def invoke1[F, I <: HList, O](f: F, i: I)
(implicit ftp: FnToProduct.Aux[F, I => O]): O = ftp(f)(i)
// So let's try to express that by extracting the input type of F as FI
def invoke2[FI, I <: HList, O](f: FI => O, i: I)
(implicit ftp: FnToProduct.Aux[FI => O, I => O]): O = ftp(f)(i)
"Invoke" should "work for a Function1" in {
// Here's our function (Int) => String
val f: (Int) => String = (i) => s"I got $i"
val l = 1 :: HNil
// this works
val r1: String = invoke1(f, l)
// So does this. (With evidence that the compiler sees the function parameter list (Int) as just Int
val r2: String = invoke2[Int, Int::HNil, String](f, l)
r1 shouldBe "I got 1"
r2 shouldBe "I got 1"
}
"Invoke" should "work for a Function2" in {
// Here's our function (String, Int) => String
val f: (String, Int) => String = (s, i) => s"I got $s and $i"
val l = "s" :: 1 :: HNil
// this works
val r1: String = invoke1(f, l)
// But this does not compile. There is no expansion for the type of FI
// (String, Int) != the function Parameter list (String, Int)
val r2: String = invoke2(f, l)
/*
Error:(...) type mismatch;
found : (String, Int) => String
required: ? => String
val r1: String = invoke1(f, l)
*/
r1 shouldBe "I got s and 1"
r2 shouldBe "I got s and 1"
}
}
【问题讨论】:
-
您知道
Function2#tupled和Function2#curried方法吗? -
是的,我是 :-) 而且 Function1 上不存在元组。大概这是因为表达 Function1 的 input 类型(作为裸类型)的能力意味着不需要元组。可怜的旧 Function2..N 缺少这个。从这个意义上说,tupled 感觉像是一种解决方法。不过,我想我想知道的是,Function1 和 2 在这方面存在差异是否有充分的理由?
标签: scala shapeless type-systems