How to correctly determine the existential for f-linked polymorphic type

There are several similar questions here, I read them and did not find an answer that could make my code work. I suppose I ended up in a corner case that requires a more accurate type specification than usual.

My business in a nutshell. I would like to create a very simple heterogeneous list to deepen my understanding of the scala language. There is a limitation that I set myself: no implications in any form, just a system like scala. Implicits can make it a lot easier, but I would like to try hard.

The code already works for me, but I would like to improve it. There he is:

sealed trait HList {
  type Self <: HList
  def self : Self

  def prepend[H](head : H) = HCons[H, Self](head, self)
  def ::[H](head : H) = prepend(head)

  type Merge[X <: HList] <: HList
  def merge[X <: HList](other : X) : Merge[X]

  def :::[X <: HList](other : X) = other.merge[Self](self)
}

sealed trait HNil extends HList {
  override type Self = HNil
  override def self = this

  override type Merge[X <: HList] = X
  override def merge[X <: HList](other : X) : Merge[X] = other
}
case object HNil extends HNil

final case class HCons[H, T <: HList](head : H, tail : T) extends HList {
  override type Self = HCons[H,T]
  override def self = this

  override type Merge[X <: HList] = HCons[H, T#Merge[X]]
  override def merge[X <: HList](other : X) : Merge[X] = HCons(head, tail.merge(other))
}

Type constructors Mergedenotes the result of a type of adding two lists. You must keep track of all nested types. Here is the result:

val x = "str" :: true :: HNil
val s : String = x.head
val b : Boolean = x.tail.head

val y = 0.5 :: 12 :: HNil
val d : Double = y.head
val i : Int = y.tail.head

val l = x ::: y
val r = y.merge(x)

val sl : String = l.head
val sb : Boolean = l.tail.head
val sd : Double = l.tail.tail.head
val si : Int = l.tail.tail.tail.head

val rd : Double = r.head
val ri : Int = r.tail.head
val rl : String = r.tail.tail.head
val rb : Boolean = r.tail.tail.tail.head

. , . , .

, Self Self. , . , f- . :

type HAny = X forSome {type X <: HList[X]}
sealed trait HList[Self <: HList[Self]] {this : Self =>
  def prepend[H](head : H) = HCons[H, Self](head, this)
  def ::[H](head : H) = prepend(head)

  type Merge[X <: HList[X]] <: HAny
  def merge[X <: HList[X]](other : X) : Merge[X]

  def :::[X <: HList[X]](other : X) = other.merge[Self](this)
}

sealed trait HNil extends HList[HNil] {
  override type Merge[X <: HList[X]] = X
  override def merge[X <: HList[X]](other : X) : Merge[X] = other
}
case object HNil extends HNil
final case class HCons[H, T <: HList[T]](head : H, tail : T) extends HList[HCons[H,T]] {
  override type Merge[X <: HList[X]] = HCons[H, T#Merge[X]]
  override def merge[X <: HList[X]](other : X) : Merge[X] = HCons[H, T#Merge[X]](head, tail.merge(other))
}

scala , :

[error] App.scala:23: type arguments [H,T#Merge[X]] do not conform to method apply type parameter bounds [H,T <: SelApp1.this.HList[T]]
[error]     override def merge[X <: HList[X]](other : X) : Merge[X] = HCons[H, T#Merge[X]](head, tail.merge(other))
[error]                                                                    ^
[error] one error found

f- . . Merge, HAny, , HList - .

, . , , HCons? , f-bound ?

+4
1

HCons, T <: HList[T] T <: HAny:

final case class HCons[H, T <: HAny](head : H, tail : T) extends HList[HCons[H,T]] { ... }
+3

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


All Articles