Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstraction over a sequence of types

Assuming we have a type T[A,B], can we express the following type constraint, let's call it HT:

every type satisfying HT must be of form T[P1, P2] :: T[P2, P3] :: T[P3, P4] :: ... :: T[PN-1, PN] :: HNil

for some type x = P1 :: P2 :: ... :: PN :: HNil.

I am trying to find an abstraction over a typed sequential processing pipeline.

like image 466
ponythewhite Avatar asked Nov 05 '14 17:11

ponythewhite


People also ask

What is abstraction and its types?

Abstraction can be of two types, namely, data abstraction and control abstraction. Data abstraction means hiding the details about the data and control abstraction means hiding the implementation details. In object-oriented approach, one can abstract both data and functions.

What is abstraction in data structure?

Data abstraction is the reduction of a particular body of data to a simplified representation of the whole. Abstraction, in general, is the process of removing characteristics from something to reduce it to a set of essential elements.

What is an abstraction in programming?

In object-oriented programming, abstraction is one of three central principles (along with encapsulation and inheritance). Through the process of abstraction, a programmer hides all but the relevant data about an object in order to reduce complexity and increase efficiency.

What is an abstraction barrier?

An abstraction barrier violation occurs whenever a part of the program that can use a higher level function instead uses a function in a lower level.


1 Answers

The most convenient way to do this kind of thing is usually to write your own type class. Here's a quick working sketch:

import shapeless._

trait T[I, O] extends (I => O)

trait Pipeline[P <: HList] {
  type In
  type Out
  type Values <: HList
}

object Pipeline {
  type Aux[P <: HList, In0, Out0, Values0 <: HList] = Pipeline[P] {
    type In = In0; type Out = Out0; type Values = Values0
  }

  def apply[P <: HList](
    implicit pipeline: Pipeline[P]
  ): Aux[P, pipeline.In, pipeline.Out, pipeline.Values] = pipeline

  implicit def onePipeline[I, O]: Aux[T[I, O] :: HNil, I, O, I :: O :: HNil] =
    new Pipeline[T[I, O] :: HNil] {
      type In = I
      type Out = O
      type Values = I :: O :: HNil
    }

  implicit def longerPipeline[I, O, P <: HList, Out0, Values0 <: HList](
    implicit pipeline: Aux[P, O, Out0, Values0]
  ): Aux[T[I, O] :: P, I, Out0, I :: Values0] =
    new Pipeline[T[I, O] :: P] {
      type In = I
      type Out = Out0
      type Values = I :: Values0
    }
}

And then (reformatted for clarity):

scala> Pipeline[T[String, Int] :: T[Int, Char] :: HNil]
res5: Pipeline[T[String, Int] :: T[Int, Char] :: HNil] {
  type In = String
  type Out = Char
  type Values = String :: Int :: Char :: HNil
} = Pipeline$$anon$2@38fd077c

scala> Pipeline[T[String, Int] :: T[Char, Char] :: HNil]
<console>:19: error: could not find implicit value for parameter
  pipeline: Pipeline[[T[String, Int] :: T[Char, Char] :: HNil]
              Pipeline[T[String, Int] :: T[Char, Char] :: HNil]
                      ^

The invalid pipeline doesn't compile, and for the valid one we get the endpoints and intermediate values correctly inferred.

like image 125
Travis Brown Avatar answered Sep 20 '22 19:09

Travis Brown