scala.collection.Map[Int, T] 的函子
Functor for scala.collection.Map[Int, T]
我正在尝试查找有关是否可以为 Map
类型创建 Functor
的信息。
文档包含有关 List
、Option
的信息,但不适用于我的情况。
能否请您告诉我是否可以创建一个 Functor[Map[Int, T]]
?
下面我将附上一个类似仿函数的实现 List
。
trait Functor[F[_]]:
def map[A, B](list: F[A])(f: A => B): F[B]
given Functor[List] with
def map[A, B](list: List[A])(f: A => B): List[B] = ???
Map[A, B]
几乎与 A => B
相同,但具有有限域。
A => B
基本上就是 Reader[A, B]
Reader[A, B]
是一个 monad
- 所有 monad 都是函子
所以,是的,让我们尝试做与 Reader
相同的事情:它只是 post- 组合给 map
:
的函数
given mapFunctor[K]: Functor[[V] =>> Map[K, V]] with
def map[A, B](m: Map[K, A])(f: A => B): Map[K, B] = m.view.mapValues(f).toMap
toMap
是必要的,因为 mapValues
是非严格的(它拒绝立即映射所有值,并将函数组合保持在符号 MapView
中)。
扩展 Luis 和 Andrey 的答案,使用 Scala 2 和 scala-cats 尝试使用类型别名
import cats.Functor
type MapInt[T] = Map[Int, T]
Functor[MapInt].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")
或使用 Scala 2 类型的 lambda "atrocity"
Functor[({type MapInt[T]=Map[Int, T]})#MapInt].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")
Functor[Map[Int, *]].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")
关于 Map
对 Functor
的错误“种类”尝试使用 REPL 来探索这个想法(如果你从 sbt console
开始它应该加载它所有的依赖项build.sbt
):
scala> import cats.Functor
import cats.Functor
scala> :kind -v Functor
cats.Functor's kind is X[F[A]]
(* -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.
scala> :kind -v Map
Map's kind is F[A1,+A2]
* -> * -(+)-> *
This is a type constructor: a 1st-order-kinded type.
scala> type MapInt[T] = Map[Int, T]
type MapInt
scala> :kind -v MapInt
MapInt's kind is F[A]
* -> *
This is a type constructor: a 1st-order-kinded type.
请注意 Functor
如何具有高阶种类
(* -> *) -> *
\______/
|
required shape of type argument to Functor
这意味着它需要一个一阶类型的类型构造函数,特别是一个接受单个类型参数的类型构造函数
* -> *
|
only one type argument expected
现在 Map
类型构造函数本身确实具有 Functor
所期望的一阶类型,但是它是错误的 arity 因为它需要两个类型参数而不是一个
1st arg to Map
|
* -> * --> *
|
2nd arg to Map
因此我们需要一个类型 lambda 来将 Map
的第一个类型参数固定为 Int
,同时保持第二个类型参数自由,这将它变成一个正确种类和元数的类型构造函数 Functor
scala> :kind -v MapInt
MapInt's kind is F[A]
* -> *
这是一个高阶类型构造函数的示例,它采用另一个二元一阶类型构造函数作为其类型参数
trait Foo[F[A, B]]
让我们检查 Map
现在是否适合而无需使用类型 lambda
scala> trait Foo[F[A, B]]
trait Foo
scala> :kind -v Foo
Foo's kind is X[F[A1,A2]]
(* -> * -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.
scala> new Foo[Map] {}
val res2: Foo[Map] = $anon@589af27e
我正在尝试查找有关是否可以为 Map
类型创建 Functor
的信息。
文档包含有关 List
、Option
的信息,但不适用于我的情况。
能否请您告诉我是否可以创建一个 Functor[Map[Int, T]]
?
下面我将附上一个类似仿函数的实现 List
。
trait Functor[F[_]]:
def map[A, B](list: F[A])(f: A => B): F[B]
given Functor[List] with
def map[A, B](list: List[A])(f: A => B): List[B] = ???
Map[A, B]
几乎与A => B
相同,但具有有限域。A => B
基本上就是Reader[A, B]
Reader[A, B]
是一个 monad- 所有 monad 都是函子
所以,是的,让我们尝试做与 Reader
相同的事情:它只是 post- 组合给 map
:
given mapFunctor[K]: Functor[[V] =>> Map[K, V]] with
def map[A, B](m: Map[K, A])(f: A => B): Map[K, B] = m.view.mapValues(f).toMap
toMap
是必要的,因为 mapValues
是非严格的(它拒绝立即映射所有值,并将函数组合保持在符号 MapView
中)。
扩展 Luis 和 Andrey 的答案,使用 Scala 2 和 scala-cats 尝试使用类型别名
import cats.Functor
type MapInt[T] = Map[Int, T]
Functor[MapInt].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")
或使用 Scala 2 类型的 lambda "atrocity"
Functor[({type MapInt[T]=Map[Int, T]})#MapInt].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")
Functor[Map[Int, *]].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")
关于 Map
对 Functor
的错误“种类”尝试使用 REPL 来探索这个想法(如果你从 sbt console
开始它应该加载它所有的依赖项build.sbt
):
scala> import cats.Functor
import cats.Functor
scala> :kind -v Functor
cats.Functor's kind is X[F[A]]
(* -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.
scala> :kind -v Map
Map's kind is F[A1,+A2]
* -> * -(+)-> *
This is a type constructor: a 1st-order-kinded type.
scala> type MapInt[T] = Map[Int, T]
type MapInt
scala> :kind -v MapInt
MapInt's kind is F[A]
* -> *
This is a type constructor: a 1st-order-kinded type.
请注意 Functor
如何具有高阶种类
(* -> *) -> *
\______/
|
required shape of type argument to Functor
这意味着它需要一个一阶类型的类型构造函数,特别是一个接受单个类型参数的类型构造函数
* -> *
|
only one type argument expected
现在 Map
类型构造函数本身确实具有 Functor
所期望的一阶类型,但是它是错误的 arity 因为它需要两个类型参数而不是一个
1st arg to Map
|
* -> * --> *
|
2nd arg to Map
因此我们需要一个类型 lambda 来将 Map
的第一个类型参数固定为 Int
,同时保持第二个类型参数自由,这将它变成一个正确种类和元数的类型构造函数 Functor
scala> :kind -v MapInt
MapInt's kind is F[A]
* -> *
这是一个高阶类型构造函数的示例,它采用另一个二元一阶类型构造函数作为其类型参数
trait Foo[F[A, B]]
让我们检查 Map
现在是否适合而无需使用类型 lambda
scala> trait Foo[F[A, B]]
trait Foo
scala> :kind -v Foo
Foo's kind is X[F[A1,A2]]
(* -> * -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.
scala> new Foo[Map] {}
val res2: Foo[Map] = $anon@589af27e