Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functor for scala.collection.Map[Int, T]

I am trying to find information if it is possible to create a Functor for a Map type. The docs have information for the List, Option, but not for my case.

Can you please tell me if it is possible to create a Functor[Map[Int, T]]?

Below I will attach an implementation of a similar functor for a 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] = ???
like image 768
Maria Avatar asked Mar 20 '26 12:03

Maria


1 Answers

Expanding Luis' and Andrey's answers, with Scala 2 and scala-cats try using type alias

import cats.Functor

type MapInt[T] = Map[Int, T]
Functor[MapInt].map(Map(1 -> "woo"))(a => a + "hoo") 
// : MapInt[String] = Map(1 -> "woohoo")

or using Scala 2 type lambda "atrocity"

Functor[({type MapInt[T]=Map[Int, T]})#MapInt].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")

or using kind-projector

Functor[Map[Int, *]].map(Map(1 -> "woo"))(a => a + "hoo")
// : MapInt[String] = Map(1 -> "woohoo")

scastie


Regarding Map being of wrong "kind" for Functor try using the REPL to explore the idea (if you start with sbt console it should load it with all the dependencies from 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.

Note how Functor has higher-order kind

(* -> *) -> *
\______/
   |
required shape of type argument to Functor

which means it expects a type constructor of first-order kind, and in particular a type constructor which takes a single type argument

* -> *
|
only one type argument expected

Now Map type constructor by itself does have first-order kind expected by Functor, however it is of wrong arity as it takes two type arguments instead of one

1st arg to Map
|
* -> * --> *
     |
   2nd arg to Map

hence we need a type lambda to fix the first type parameter of Map to Int whilst keeping second type parameter free which turns it into a type constructor of the correct kind and arity for Functor

scala> :kind -v MapInt
MapInt's kind is F[A]
* -> *

Here is an example of a higher-order type constructor which takes another binary-arity first-order type constructor as its type argument

trait Foo[F[A, B]]

Let's check if Map now fits without having to use a type 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$1@589af27e
like image 136
Mario Galic Avatar answered Mar 22 '26 04:03

Mario Galic