问题描述
def explode[A,B](f: A => List[B]): List[A => B]
相反的方向是可能的:
def nest[A,B](fs: List[A => B]): A => List[B] = (a: A) => fs.map(_(a))
现在我倾向于相信第一个 (explode
) 是无法实现的,但我很高兴被证明是错误的。如果确实无法实施,是否有深层次的原因?
在我看来,我本质上是要求编译器将输入 A
“复制”一些 n
次(List
的大小),并将其“修复”为输入。
解决方法
在我看来,我本质上是要求编译器将输入 A
“复制”一些 n
次(List
的大小),并将其“修复”为输入。
问题是你不知道 n
是什么。例如,考虑一个函数,它返回一个数字的所有质数除数的列表:
def divisors(n: Int): List[Int] = ???
您希望 explode(divisors)
是什么? divisors
可以返回任意大小的 List
,具体取决于它的参数,无论何时在未来调用它。但是当您调用 explode
时,它必须立即返回一个固定大小的 List
。
给定一个固定类型 A
,你的代码中的签名可以这样写:
type F[T] = List[T]
type G[T] = A => T
def nest[B]: F[G[B]] => G[F[B]]
def explode[B]: G[F[B]] => F[G[B]]
nest
和 explode
让人想起 sequence
操作。它适用于 nest
,因为可以为 List
编写 Traverse
实例,但无法为函数 Traverse
编写 A => T
实例.这是一个等效的 question for Haskell,可以提供更多见解。
如果你想做一些满足签名的实现,你可以这样做:
def explode[A,B](f: A => List[B]): List[A => B] = {
Nil
}
def explode[A,B](f: A => List[B]): List[A => B] = {
List(f.andThen(_.head))
}
但我猜你想要一些语义上不同的东西:
“重复”输入 A n 次(列表大小),并“修复”它 作为输入
那样的话,就有问题了。在一般情况下,f
的结果取决于输入 A
。它可以是 Nil、有限大小列表或无限列表。
你能做的就是:
def explode[A,B](f: A => List[B]): A => List[A => B] = {
f.andThen(_.map(b => (_: A) => b)
}