Scala Type Class Guidelines

I read and work my way through type classes, and I came across this way of defining type classes from the Shapeless tutorial:

So here is an example:

object CsvEncoder {
  // "Summoner" method
  def apply[A](implicit enc: CsvEncoder[A]): CsvEncoder[A] =
    enc
  // "Constructor" method
  def instance[A](func: A => List[String]): CsvEncoder[A] =
    new CsvEncoder[A] {
      def encode(value: A): List[String] =
        func(value)
      }
    // Globally visible type class instances
}

What I don’t understand is the need to use the method? What does he do in this context above?

The rest of the manual describes how I can instantiate a class of type:

implicit val booleanEncoder: CsvEncoder[Boolean] =
  new CsvEncoder[Boolean] {
    def encode(b: Boolean): List[String] =
      if(b) List("yes") else List("no") 
  } 

actually shortened to:

implicit val booleanEncoder: CsvEncoder[Boolean] =
instance(b => if(b) List("yes") else List("no"))

So now my question is: how does it work? What I am not getting is the need to apply the method?

EDIT: I came across a blog post that describes the steps for creating type classes, as shown below:

  • Define the specification of the contract class Foo.
  • - Foo -, , Foo, , .
  • FooOps, .
  • FooSyntax, FooOps Foo.

, 2, 3 4?

+4
3

Haskell ( Haskell - ), . ,

2) @Alexey Romanov, apply , implicitly[CsvEncoder[IceCream]] CsvEncoder[IceCream] (aka CsvEncoder.apply[IceCream]()), - .

3) FooOps DSL. , - :

trait Semigroup[A] {
   ...
   def append(a: A, b: A)
}

import implicits._ //you should import actual instances for `Semigroup[Int]` etc.
implicitly[Semigroup[Int]].append(2,2)

append(2,2), :

  trait Ops[A] {
    def typeClassInstance: Semigroup[A]
    def self: A
    def |+|(y: A): A = typeClassInstance.append(self, y)
  }

  trait ToSemigroupOps {
    implicit def toSemigroupOps[A](target: A)(implicit tc: Semigroup[A]): Ops[A] = new Ops[A] {
      val self = target
      val typeClassInstance = tc
    }
  }

  object SemiSyntax extends ToSemigroupOps

4) :

import SemiSyntax._ 
import implicits._ //you should also import actual instances for `Semigroup[Int]` etc.

2 |+| 2

, scala implicit class - , implicit class DSL - - () , ( ) ..

, : https://github.com/mpilquist/simulacrum.


CsvEncoder , instance -, apply () . , ( ), ( , ).

+3

object CsvEncoder:

apply... :

CsvEncoder[IceCream]
// res9: CsvEncoder[IceCream] = ...
+1

: apply cuter.

, , Generic case Foo.

trait Generic[T] {
  type Repr
}
object Generic {
  def apply[T](implicit gen: Generic[T]): Generic[T] { type Repr = gen.Repr } = gen

  /* lots of macros to generate implicit instances omitted */
}

case class Foo(a: Int, b: String)

, Generic[Foo], , Generic[Foo] { type Repr = Int :: String :: HNil }. implicitly[Generic[Foo]], , a Generic[Foo]. : Repr , . , implicitly :

def implicitly[T](implicit e: T): T = e

: T, T, , . , implicitly[Generic[Foo] { type Repr = Int :: String :: HNil }], .

+1

Source: https://habr.com/ru/post/1675560/


All Articles