`A => List[B]` 可以转换为 `List[A => B]` 吗?

问题描述

我正在尝试为这个 Scala 函数签名找到一个实现:

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]]

nestexplode 让人想起 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)
}