├── project ├── build.properties └── plugins.sbt ├── .gitignore ├── src ├── main │ └── scala │ │ ├── codata │ │ ├── CobindKlass.scala │ │ ├── CozipKlass.scala │ │ ├── CoapplicativeK.scala │ │ ├── ComonadK.scala │ │ ├── CopointedKlass.scala │ │ ├── ComonadKlass.scala │ │ ├── CoapplyKlass.scala │ │ ├── CoapplyK.scala │ │ ├── CoapplicativeKlass.scala │ │ ├── CopointedK.scala │ │ ├── CobindK.scala │ │ ├── CopKNat.scala │ │ ├── Cohierarchy.scala │ │ ├── CopKBuild.scala │ │ ├── CozipK.scala │ │ └── CopK.scala │ │ ├── package.scala │ │ └── data │ │ ├── ZipKlass.scala │ │ ├── MonadK.scala │ │ ├── PointedKlass.scala │ │ ├── ApplyKlass.scala │ │ ├── BindKlass.scala │ │ ├── MonadKlass.scala │ │ ├── FunctorKlass.scala │ │ ├── ApplicativeKlass.scala │ │ ├── PointedK.scala │ │ ├── ApplicativeK.scala │ │ ├── ApplyK.scala │ │ ├── FunctorK.scala │ │ ├── BindK.scala │ │ ├── ZipK.scala │ │ └── Hierarchy.scala └── test │ └── scala │ └── KhatsSpec.scala ├── LICENSE ├── README.md └── COPYING /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.8 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0") 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target/ 3 | lib_managed/ 4 | src_managed/ 5 | project/boot/ 6 | .history 7 | .cache 8 | -------------------------------------------------------------------------------- /src/main/scala/codata/CobindKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait CobindKlass[T[_[_], _]] extends CobindK[T] with CoapplyKlass[T] -------------------------------------------------------------------------------- /src/main/scala/package.scala: -------------------------------------------------------------------------------- 1 | import scala.language.implicitConversions 2 | 3 | 4 | package object khats extends Cohierarchy with Hierarchy 5 | -------------------------------------------------------------------------------- /src/main/scala/data/ZipKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait ZipKlass[T[_[_], _]] extends ZipK[T] { 4 | 5 | final def zipk: ZipK[T] = this 6 | } -------------------------------------------------------------------------------- /src/main/scala/data/MonadK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait MonadK[T[_[_], _]] { 5 | 6 | def bindk: BindK[T] 7 | def applicativek: ApplicativeK[T] 8 | 9 | } -------------------------------------------------------------------------------- /src/main/scala/codata/CozipKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait CozipKlass[T[_[_], _]] 4 | extends CozipK[T] { 5 | 6 | final def cozipk: CozipK[T] = this 7 | 8 | } -------------------------------------------------------------------------------- /src/main/scala/codata/CoapplicativeK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait CoapplicativeK[T[_[_], _]] { 4 | 5 | def copointedk: CopointedK[T] 6 | def coapplyk: CoapplyK[T] 7 | } -------------------------------------------------------------------------------- /src/main/scala/data/PointedKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait PointedKlass[T[_[_], _]] 4 | extends PointedK[T] { 5 | 6 | final def pointedk: PointedK[T] = this 7 | } -------------------------------------------------------------------------------- /src/main/scala/codata/ComonadK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait ComonadK[T[_[_], _]] { 5 | 6 | def cobindk: CobindK[T] 7 | def coapplicativek: CoapplicativeK[T] 8 | 9 | } -------------------------------------------------------------------------------- /src/main/scala/data/ApplyKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait ApplyKlass[T[_[_], _]] extends ApplyK[T] with FunctorK[T] { 5 | 6 | def applyk: ApplyK[T] = this 7 | 8 | } -------------------------------------------------------------------------------- /src/main/scala/data/BindKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait BindKlass[T[_[_], _]] extends BindK[T] with ApplyKlass[T] { 5 | 6 | final def bindk: BindK[T] = this 7 | 8 | } -------------------------------------------------------------------------------- /src/main/scala/codata/CopointedKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait CopointedKlass[T[_[_], _]] 4 | extends CopointedK[T] { 5 | 6 | final def copointedk: CopointedK[T] = this 7 | 8 | } -------------------------------------------------------------------------------- /src/main/scala/data/MonadKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait MonadKlass[T[_[_], _]] extends MonadK[T] with BindKlass[T] with ApplicativeKlass[T] { 5 | 6 | final def monadk: MonadK[T] = this 7 | 8 | } -------------------------------------------------------------------------------- /src/main/scala/data/FunctorKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait FunctorKlass[T[_[_], _]] 7 | extends FunctorK[T] { 8 | 9 | final def functork: FunctorK[T] = this 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/codata/ComonadKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait ComonadKlass[T[_[_], _]] extends ComonadK[T] with CobindKlass[T] with CoapplicativeKlass[T] { 5 | 6 | final def comonadk: ComonadK[T] = this 7 | 8 | } -------------------------------------------------------------------------------- /src/main/scala/data/ApplicativeKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait ApplicativeKlass[T[_[_], _]] extends ApplicativeK[T] with ApplyKlass[T] with PointedK[T] { 5 | 6 | final def applicativek: ApplicativeK[T] = this 7 | } -------------------------------------------------------------------------------- /src/main/scala/codata/CoapplyKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait CoapplyKlass[T[_[_], _]] 4 | extends CoapplyK[T] 5 | with CozipKlass[T] 6 | with FunctorKlass[T] { 7 | 8 | final def coapplyk: CoapplyK[T] = this 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/scala/codata/CoapplyK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait CoapplyK[T[_[_], _]] { 4 | 5 | def functork: FunctorK[T] 6 | def cozipk: CozipK[T] 7 | 8 | } 9 | 10 | 11 | object CoapplyK { 12 | 13 | def apply[T[_[_], _]](implicit c: CoapplyK[T]) = c 14 | 15 | } -------------------------------------------------------------------------------- /src/main/scala/data/PointedK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait PointedK[T[_[_], _]] { 7 | def purek[F[_]]: F ~> T[F, ?] 8 | } 9 | 10 | object PointedK { 11 | 12 | def apply[T[_[_], _]](implicit p: PointedK[T]): PointedK[T] = p 13 | 14 | } -------------------------------------------------------------------------------- /src/main/scala/codata/CoapplicativeKlass.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | trait CoapplicativeKlass[T[_[_], _]] 4 | extends CoapplicativeK[T] 5 | with CoapplyKlass[T] 6 | with CopointedKlass[T] { 7 | 8 | final def coapplicativek: CoapplicativeKlass[T] = this 9 | } 10 | -------------------------------------------------------------------------------- /src/main/scala/codata/CopointedK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait CopointedK[T[_[_], _]] { 7 | def copurek[F[_]]: T[F, ?] ~> F 8 | } 9 | 10 | object CopointedK { 11 | 12 | def apply[T[_[_], _]](implicit p: CopointedK[T]): CopointedK[T] = p 13 | 14 | } -------------------------------------------------------------------------------- /src/main/scala/data/ApplicativeK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait ApplicativeK[T[_[_], _]] { 5 | 6 | def applyk: ApplyK[T] 7 | def pointedk: PointedK[T] 8 | 9 | } 10 | 11 | object ApplicativeK { 12 | 13 | def apply[T[_[_], _]](implicit a: ApplicativeK[T]): ApplicativeK[T] = a 14 | } -------------------------------------------------------------------------------- /src/main/scala/data/ApplyK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait ApplyK[T[_[_], _]] { 7 | 8 | def functork: FunctorK[T] 9 | def zipk: ZipK[T] 10 | 11 | } 12 | 13 | 14 | object ApplyK { 15 | 16 | def apply[T[_[_], _]](implicit a: ApplyK[T]): ApplyK[T] = a 17 | 18 | } -------------------------------------------------------------------------------- /src/main/scala/data/FunctorK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait FunctorK[T[_[_], _]] { 7 | def mapk[F[_], G[_]](tfa: F ~> G): T[F, ?] ~> T[G, ?] 8 | } 9 | 10 | 11 | object FunctorK { 12 | 13 | def apply[T[_[_], _]](implicit f: FunctorK[T]): FunctorK[T] = f 14 | 15 | } -------------------------------------------------------------------------------- /src/main/scala/data/BindK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait BindK[T[_[_], _]] { 7 | 8 | def applyk: ApplyK[T] 9 | 10 | def bindk[F[_]]: T[T[F, ?], ?] ~> T[F, ?] 11 | 12 | } 13 | 14 | object BindK { 15 | 16 | def apply[T[_[_], _]](implicit a: BindK[T]): BindK[T] = a 17 | 18 | } -------------------------------------------------------------------------------- /src/main/scala/codata/CobindK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait CobindK[T[_[_], _]] { 7 | 8 | def coapplyk: CoapplyK[T] 9 | 10 | def cobindk[F[_]]: T[F, ?] ~> T[T[F, ?], ?] 11 | 12 | } 13 | 14 | object CobindK { 15 | 16 | def apply[T[_[_], _]](implicit a: CobindK[T]): CobindK[T] = a 17 | 18 | } -------------------------------------------------------------------------------- /src/main/scala/data/ZipK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait ZipK[T[_[_], _]] { 7 | 8 | // Temporary until we have ProductK 9 | def zipk2[F[_], G[_]]: λ[t => (T[F, t], T[G, t])] ~> T[λ[t => (F[t], G[t])], ?] 10 | 11 | } 12 | 13 | object ZipK { 14 | 15 | def apply[T[_[_], _]](implicit c: ZipK[T]): ZipK[T] = c 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/scala/codata/CopKNat.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | trait CopKNat[C[_] <: CopK[_]] { 6 | 7 | def replace[F[_], G[_], D[_] <: CopK[_]](nat: F ~> G)( 8 | implicit replaceF: Replace.Aux[C, F, G, D] 9 | ): C ~> D = new (C ~> D) { 10 | def apply[A](ca: C[A]): D[A] = replaceF.replace(ca)(nat) 11 | } 12 | 13 | } 14 | 15 | object CopKNat { 16 | def apply[C[_] <: CopK[_]] = new CopKNat[C] {} 17 | } 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This software is licensed under the Apache 2 license, quoted below. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with 4 | the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. 5 | 6 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an 7 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 8 | language governing permissions and limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Khats, cats on higher-kinded amphets 2 | 3 | This is a study on structures from Category Theory applied to higher-kinded structures. 4 | 5 | For example: 6 | 7 | ```scala 8 | type T[_[_], _] 9 | 10 | val nat: F ~> G = ??? 11 | 12 | FunctorK[T].mapk(nat) 13 | ``` 14 | 15 | It provides a set of typeclasses for higher-kinded structures based on cats FunctionK/Natural Transformation and following the typeclass design imagined by Alois Cochard in [Scato project](https://github.com/aloiscochard/scato) and also used in [Scalaz 8.0.x branch](https://github.com/scalaz/scalaz/tree/series/8.0.x). 16 | 17 | Do you wonder whether it's useful or just brainfucking? 18 | 19 | I wonder too yet the brain effort is fun and I have a few interesting ideas in mind to dig and the code is still very experimental... Let's take it as an exercise of style until it becomes more (or not)! -------------------------------------------------------------------------------- /src/main/scala/data/Hierarchy.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait Hierarchy extends Hierarchy3 5 | 6 | 7 | trait Hierarchy3 extends Hierarchy2 { 8 | 9 | implicit def MonadKBindk[T[_[_], _]](implicit s: MonadK[T]): BindK[T] = s.bindk 10 | implicit def MonadKApplicativek[T[_[_], _]](implicit s: MonadK[T]): ApplicativeK[T] = s.applicativek 11 | implicit def MonadKFunctork[T[_[_], _]](implicit s: MonadK[T]): FunctorK[T] = s.applicativek.applyk.functork 12 | 13 | } 14 | 15 | trait Hierarchy2 extends Hierarchy1 { 16 | 17 | implicit def BindKApplyk[T[_[_], _]](implicit s: BindK[T]): ApplyK[T] = s.applyk 18 | implicit def BindKFunctork[T[_[_], _]](implicit s: BindK[T]): FunctorK[T] = s.applyk.functork 19 | 20 | } 21 | 22 | trait Hierarchy1 extends Hierarchy0 { 23 | 24 | implicit def ApplicativeKCoapplyk[T[_[_], _]](implicit s: ApplicativeK[T]) = s.applyk 25 | implicit def ApplicativeKFunctork[T[_[_], _]](implicit s: ApplicativeK[T]) = s.applyk.functork 26 | 27 | } 28 | 29 | trait Hierarchy0 { 30 | 31 | implicit def ApplyKFunctork[T[_[_], _]](implicit s: ApplyK[T]) = s.functork 32 | 33 | } -------------------------------------------------------------------------------- /src/main/scala/codata/Cohierarchy.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | trait Cohierarchy extends Cohierarchy3 5 | 6 | trait Cohierarchy3 extends Cohierarchy2 { 7 | 8 | implicit def ComonadKBindk[T[_[_], _]](implicit s: ComonadK[T]): CobindK[T] = s.cobindk 9 | implicit def ComonadKApplicativek[T[_[_], _]](implicit s: ComonadK[T]): CoapplicativeK[T] = s.coapplicativek 10 | implicit def ComonadKFunctork[T[_[_], _]](implicit s: ComonadK[T]): FunctorK[T] = s.coapplicativek.coapplyk.functork 11 | 12 | } 13 | 14 | trait Cohierarchy2 extends Cohierarchy1 { 15 | 16 | implicit def CobindKApplyk[T[_[_], _]](implicit s: CobindK[T]): CoapplyK[T] = s.coapplyk 17 | implicit def CobindKFunctork[T[_[_], _]](implicit s: CobindK[T]): FunctorK[T] = s.coapplyk.functork 18 | 19 | } 20 | 21 | 22 | trait Cohierarchy1 extends Cohierarchy0 { 23 | 24 | implicit def CoapplicativeKCoapplyk[T[_[_], _]](implicit s: CoapplicativeK[T]) = s.coapplyk 25 | implicit def CoapplicativeKFunctork[T[_[_], _]](implicit s: CoapplicativeK[T]) = s.coapplyk.functork 26 | 27 | } 28 | 29 | trait Cohierarchy0 { 30 | 31 | implicit def CoapplyKFunctork[T[_[_], _]](implicit s: CoapplyK[T]) = s.functork 32 | 33 | } -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Cats Copyright (c) 2016 Pascal Voitot. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | ------ 22 | 23 | Code in khats is derived from Scalaz (branch 8.0.x) based on work by Alois Cochard on Scato project and Scala Cats too. 24 | -------------------------------------------------------------------------------- /src/main/scala/codata/CopKBuild.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | 4 | sealed trait CopKBuild 5 | 6 | class :|:[H[_], T <: CopKBuild](implicit val toCop:ToCopK[H :|: T]) extends CopKBuild 7 | 8 | trait :||:[T1 <: CopKBuild, T2 <: CopKBuild] extends CopKBuild 9 | 10 | trait NilK extends CopKBuild 11 | 12 | 13 | class CopKBuilder[CopKBuild0 <: CopKBuild, C[_] <: CopK[_]] { 14 | type Cop[t] = C[t] 15 | } 16 | 17 | object CopKBuilder { 18 | def apply[CopKBuild0 <: CopKBuild](implicit toCop:ToCopK[CopKBuild0]) = new CopKBuilder[CopKBuild0, toCop.Cop] {} 19 | } 20 | 21 | trait ToCopK[F <: CopKBuild] { 22 | type Cop[_] <: CopK[_] 23 | } 24 | 25 | object ToCopK extends LowerToCopK { 26 | 27 | def apply[F <: CopKBuild](implicit toCopK: ToCopK[F]) = toCopK 28 | 29 | type Aux[F <: CopKBuild, C[_] <: CopK[_]] = ToCopK[F] { 30 | type Cop[t] = C[t] 31 | } 32 | 33 | implicit val NilK: ToCopK.Aux[NilK, CNilK] = new ToCopK[NilK] { 34 | type Cop[t] = CNilK[t] 35 | } 36 | 37 | implicit def one[H[_]]: ToCopK.Aux[:|:[H, NilK], In1[H, ?]] = 38 | new ToCopK[:|:[H, NilK]] { 39 | type Cop[t] = In1[H, t] 40 | } 41 | 42 | implicit def two[H[_], H2[_]]: ToCopK.Aux[:|:[H, :|:[H2, NilK]], In2[H, H2, ?]] = 43 | new ToCopK[:|:[H, :|:[H2, NilK]]] { 44 | type Cop[t] = In2[H, H2, t] 45 | } 46 | 47 | implicit def three[H[_], H2[_], H3[_]]: ToCopK.Aux[:|:[H, :|:[H2, :|:[H3, NilK]]], In3[H, H2, H3, ?]] = 48 | new ToCopK[:|:[H, :|:[H2, :|:[H3, NilK]]]] { 49 | type Cop[t] = In3[H, H2, H3, t] 50 | } 51 | 52 | } 53 | 54 | trait LowerToCopK { 55 | 56 | implicit def rec[H[_], T <: CopKBuild, C[_] <: CopK[_], O[_] <: CopK[_]]( 57 | implicit 58 | next: ToCopK.Aux[T, C] 59 | , prep: PrependHK.Aux[H, C, O] 60 | ): ToCopK.Aux[:|:[H, T], O] = 61 | new ToCopK[:|:[H, T]] { 62 | type Cop[t] = O[t] 63 | } 64 | 65 | implicit def merge[T1 <: CopKBuild, T2 <: CopKBuild, C1[_] <: CopK[_], C2[_] <: CopK[_]]( 66 | implicit 67 | toCopK1: ToCopK.Aux[T1, C1] 68 | , toCopK2: ToCopK.Aux[T2, C2] 69 | ): ToCopK.Aux[:||:[T1, T2], AppendK[C1, C2, ?]] = 70 | new ToCopK[:||:[T1, T2]] { 71 | type Cop[t] = AppendK[C1, C2, t] 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/scala/codata/CozipK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | 5 | 6 | trait CozipK[T[_[_], _]] { 7 | 8 | def cozipk2[F[_], G[_]]: T[In2[F, G, ?], ?] ~> In2[T[F, ?], T[G, ?], ?] 9 | 10 | def cozipk[C[_] <: CopK[_]](implicit coZipper: CoZipperK[T, C]): T[C, ?] ~> coZipper.Out = coZipper.cozipk 11 | 12 | } 13 | 14 | object CozipK { 15 | 16 | def apply[T[_[_], _]](implicit c: CozipK[T]): CozipK[T] = c 17 | 18 | } 19 | 20 | trait CoZipperK[T[_[_], _], C[_] <: CopK[_]] { 21 | type Out[_] <: CopK[_] 22 | 23 | def cozipk: T[C, ?] ~> Out 24 | } 25 | 26 | object CoZipperK { 27 | 28 | type Aux[T[_[_], _], C[_] <: CopK[_], D[_] <: CopK[_]] = CoZipperK[T, C] { type Out[t] = D[t] } 29 | 30 | implicit def two[T[_[_], _], F[_], G[_]]( 31 | implicit coz: CozipK[T] 32 | ) = new CoZipperK[T, In2[F, G, ?]] { 33 | type Out[t] = In2[T[F, ?], T[G, ?], t] 34 | 35 | val cozipk = coz.cozipk2[F, G] 36 | } 37 | 38 | implicit def three[T[_[_], _], F[_], G[_], H[_]]( 39 | implicit 40 | coz: CozipK[T] 41 | , functork: FunctorK[T] 42 | ) = new CoZipperK[T, In3[F, G, H, ?]] { 43 | type Out[t] = In3[T[F, ?], T[G, ?], T[H, ?], t] 44 | 45 | val nat = functork.mapk(new (In3[F, G, H, ?] ~> In2[F, In2[G, H, ?], ?]) { 46 | def apply[A](t: In3[F, G, H, A]): In2[F, In2[G, H, ?], A] = { 47 | t match { 48 | case In3l(l) => In2l(l) 49 | case In3m(m) => In2r(In2l(m)) 50 | case In3r(r) => In2r(In2r(r)) 51 | } 52 | } 53 | }) 54 | 55 | val cozipk = new (T[In3[F, G, H, ?], ?] ~> In3[T[F, ?], T[G, ?], T[H, ?], ?]) { 56 | def apply[A](t: T[In3[F, G, H, ?], A]): In3[T[F, ?], T[G, ?], T[H, ?], A] = { 57 | coz.cozipk2[F, In2[G, H, ?]](nat(t)) match { 58 | case In2l(l) => In3l(l) 59 | case In2r(r) => coz.cozipk2[G, H](r) match { 60 | case In2l(l) => In3m(l) 61 | case In2r(r) => In3r(r) 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | implicit def rec[T[_[_], _], L[_] <: CopK[_], R[_] <: CopK[_], LO[_] <: CopK[_], RO[_] <: CopK[_]]( 69 | implicit 70 | coz: CozipK[T] 71 | , functork: FunctorK[T] 72 | , nextL: CoZipperK.Aux[T, L, LO] 73 | , nextR: CoZipperK.Aux[T, R, RO] 74 | ) = new CoZipperK[T, AppendK[L, R, ?]] { 75 | type Out[t] = AppendK[LO, RO, t] 76 | 77 | val nat = functork.mapk(new (AppendK[L, R, ?] ~> In2[L, R, ?]) { 78 | def apply[A](t: AppendK[L, R, A]): In2[L, R, A] = { 79 | t match { 80 | case Aplk(l) => In2l(l) 81 | case Aprk(r) => In2r(r) 82 | } 83 | } 84 | }) 85 | 86 | val cozipk = new (T[AppendK[L, R, ?], ?] ~> AppendK[LO, RO, ?]) { 87 | def apply[A](t: T[AppendK[L, R, ?], A]): AppendK[LO, RO, A] = { 88 | coz.cozipk2[L, R](nat(t)) match { 89 | case In2l(l) => Aplk(nextL.cozipk(l)) 90 | case In2r(r) => Aprk(nextR.cozipk(r)) 91 | } 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/test/scala/KhatsSpec.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.free.Free 4 | 5 | import org.scalatest._ 6 | 7 | import cats.free.{Free, Trampoline} 8 | import cats.data.Xor 9 | import cats.{~>, Id} 10 | 11 | import scala.concurrent._ 12 | import scala.concurrent.duration._ 13 | 14 | import cats.Functor 15 | import cats.std.future._ 16 | import cats.std.option._ 17 | import cats.std.list._ 18 | import ExecutionContext.Implicits.global 19 | 20 | import scala.language.reflectiveCalls 21 | 22 | 23 | 24 | sealed trait Foo[F[_], A] 25 | 26 | object Foo { 27 | 28 | case class Foo0[F[_], A](val fa: F[A]) extends Foo[F, A] 29 | 30 | implicit val copointedk = new CopointedKlass[Foo] { 31 | def copurek[F[_]]: Foo[F, ?] ~> F = new (Foo[F, ?] ~> F) { 32 | def apply[A](tfa: Foo[F, A]): F[A] = tfa match { 33 | case Foo0(fa) => fa 34 | } 35 | } 36 | } 37 | 38 | implicit val pointedk = new PointedKlass[Foo] { 39 | def purek[F[_]]: F ~> Foo[F, ?] = new (F ~> Foo[F, ?]) { 40 | def apply[A](fa: F[A]): Foo[F, A] = Foo0(fa) 41 | } 42 | } 43 | 44 | 45 | implicit val functork = new FunctorKlass[Foo] { 46 | def mapk[F[_], G[_]](nat: F ~> G) = new (Foo[F, ?] ~> Foo[G, ?]) { 47 | def apply[A](fa: Foo[F, A]): Foo[G, A] = fa match { 48 | case Foo0(fa) => Foo0(nat(fa)) 49 | } 50 | } 51 | } 52 | 53 | implicit val cozipk = new CozipKlass[Foo] { 54 | def cozipk2[F[_], G[_]] = new (Foo[In2[F, G, ?], ?] ~> In2[Foo[F, ?], Foo[G, ?], ?]) { 55 | def apply[A](foo: Foo[In2[F, G, ?], A]): In2[Foo[F, ?], Foo[G, ?], A] = foo match { 56 | case Foo0(f) => f match { 57 | case In2l(l) => In2l(Foo0(l)) 58 | case In2r(r) => In2r(Foo0(r)) 59 | } 60 | } 61 | } 62 | } 63 | 64 | } 65 | 66 | object FreeHK { 67 | 68 | implicit val functork = new FunctorKlass[Free] { 69 | def mapk[F[_], G[_]](nat: F ~> G) = new (Free[F, ?] ~> Free[G, ?]) { 70 | def apply[A](fa: Free[F, A]): Free[G, A] = fa.mapSuspension(nat) 71 | } 72 | } 73 | 74 | implicit val pointedk = new PointedKlass[Free] { 75 | def purek[F[_]]: F ~> Free[F, ?] = new (F ~> Free[F, ?]) { 76 | def apply[A](fa: F[A]): Free[F, A] = Free.liftF(fa) 77 | } 78 | } 79 | 80 | } 81 | 82 | 83 | class KhatsSpec extends FlatSpec with Matchers { 84 | 85 | "KhatsSpec" should "cozip it" in { 86 | type C = Option :|: List :|: NilK 87 | val C = CopKBuilder[C] 88 | 89 | val i = CozipK[Foo].cozipk[C.Cop].apply(Foo.Foo0(In2r(List(5)))) 90 | println(i) 91 | } 92 | 93 | it should "free functork" in { 94 | import FreeHK._ 95 | 96 | implicit class PureK[F[_], A](fa: F[A]) { 97 | def purek[T[_[_], _]](implicit pk: PointedK[T]) = pk.purek(fa) 98 | } 99 | 100 | implicit class MapK[T[_[_], _], F[_], A](tfa: T[F, A])(implicit fk: FunctorK[T]) { 101 | def mapk[G[_]](nat: F ~> G) = fk.mapk(nat)(tfa) 102 | } 103 | 104 | Option(5).purek[Free].mapk( 105 | new (Option ~> List) { 106 | def apply[A](s: Option[A]) = s.toList 107 | } 108 | ) 109 | 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/scala/codata/CopK.scala: -------------------------------------------------------------------------------- 1 | package khats 2 | 3 | import cats.~> 4 | import cats.data.Xor 5 | 6 | /** Higher-Kinded Coproduct (exactly like shapeless Coproduct but higher-kinded) 7 | * 8 | * Using shapeless syntax, it represents a M[t] = F[t] :+: G[t] :+: H[t] :+: CNilk[t] 9 | */ 10 | sealed trait CopK[A] extends Product with Serializable 11 | 12 | sealed trait CNilK[A] extends CopK[A] 13 | 14 | // sealed trait ConsK[H[_], L[_] <: CopK[_], A] extends CopK[A] { 15 | // type Cop[t] = ConsK[H, L, t] 16 | // } 17 | // final case class Inlk[H[_], T[_] <: CopK[_], A](head : H[A]) extends ConsK[H, T, A] 18 | // final case class Inrk[H[_], T[_] <: CopK[_], A](tail : T[A]) extends ConsK[H, T, A] 19 | 20 | final case class In1[H[_], A](head: H[A]) extends CopK[A] 21 | 22 | sealed trait In2[H1[_], H2[_], A] extends CopK[A] 23 | final case class In2l[H1[_], H2[_], A](left: H1[A]) extends In2[H1, H2, A] 24 | final case class In2r[H1[_], H2[_], A](right: H2[A]) extends In2[H1, H2, A] 25 | 26 | sealed trait In3[H1[_], H2[_], H3[_], A] extends CopK[A] 27 | final case class In3l[H1[_], H2[_], H3[_], A](left: H1[A]) extends In3[H1, H2, H3, A] 28 | final case class In3m[H1[_], H2[_], H3[_], A](middle: H2[A]) extends In3[H1, H2, H3, A] 29 | final case class In3r[H1[_], H2[_], H3[_], A](right: H3[A]) extends In3[H1, H2, H3, A] 30 | 31 | // Used to lazily delays CopK flattening as long as possible 32 | sealed trait AppendK[L[_] <: CopK[_], R[_] <: CopK[_], A] extends CopK[A] 33 | final case class Aplk[L[_] <: CopK[_], R[_] <: CopK[_], A](left: L[A]) extends AppendK[L, R, A] 34 | final case class Aprk[L[_] <: CopK[_], R[_] <: CopK[_], A](right: R[A]) extends AppendK[L, R, A] 35 | 36 | trait ContainsHK[L[_] <: CopK[_], H[_]] extends Serializable { 37 | def extract[A](la: L[A]): Option[H[A]] 38 | def build[A](ha: H[A]): L[A] 39 | } 40 | 41 | 42 | object ContainsHK extends LowerContainsHK { 43 | 44 | def apply[L[_] <: CopK[_], H[_]] 45 | (implicit containsHK: ContainsHK[L, H])/*: Aux[L, H, containsHK.R]*/ = containsHK 46 | 47 | implicit def in1[H[_]]: ContainsHK[In1[H, ?], H] = 48 | new ContainsHK[In1[H, ?], H] { 49 | 50 | def extract[A](la: In1[H, A]): Option[H[A]] = Some(la.head) 51 | 52 | def build[A](ha: H[A]): In1[H, A] = In1(ha) 53 | } 54 | 55 | implicit def in2[H1[_], H2[_]]: ContainsHK[In2[H1, H2, ?], H1] = 56 | new ContainsHK[In2[H1, H2, ?], H1] { 57 | 58 | def extract[A](la: In2[H1, H2, A]): Option[H1[A]] = la match { 59 | case In2l(l) => Some(l) 60 | case In2r(r) => None 61 | } 62 | 63 | def build[A](ha: H1[A]): In2[H1, H2, A] = In2l(ha) 64 | } 65 | 66 | implicit def in3l[H1[_], H2[_], H3[_]]: ContainsHK[In3[H1, H2, H3, ?], H1] = 67 | new ContainsHK[In3[H1, H2, H3, ?], H1] { 68 | 69 | def extract[A](la: In3[H1, H2, H3, A]): Option[H1[A]] = la match { 70 | case In3l(l) => Some(l) 71 | case In3m(_) => None 72 | case In3r(_) => None 73 | } 74 | 75 | def build[A](ha: H1[A]): In3[H1, H2, H3, A] = In3l(ha) 76 | } 77 | 78 | } 79 | 80 | trait LowerContainsHK extends LowerContainsHK2 { 81 | 82 | implicit def in2r[H1[_], H2[_]]: ContainsHK[In2[H1, H2, ?], H2] = 83 | new ContainsHK[In2[H1, H2, ?], H2] { 84 | 85 | def extract[A](la: In2[H1, H2, A]): Option[H2[A]] = la match { 86 | case In2l(l) => None 87 | case In2r(r) => Some(r) 88 | } 89 | 90 | def build[A](ha: H2[A]): In2[H1, H2, A] = In2r(ha) 91 | } 92 | 93 | implicit def in3m[H1[_], H2[_], H3[_]]: ContainsHK[In3[H1, H2, H3, ?], H2] = 94 | new ContainsHK[In3[H1, H2, H3, ?], H2] { 95 | 96 | def extract[A](la: In3[H1, H2, H3, A]): Option[H2[A]] = la match { 97 | case In3l(l) => None 98 | case In3m(m) => Some(m) 99 | case In3r(_) => None 100 | } 101 | 102 | def build[A](ha: H2[A]): In3[H1, H2, H3, A] = In3m(ha) 103 | } 104 | 105 | } 106 | 107 | 108 | trait LowerContainsHK2 extends LowerContainsHK3 { 109 | 110 | implicit def in3r[H1[_], H2[_], H3[_]]: ContainsHK[In3[H1, H2, H3, ?], H3] = 111 | new ContainsHK[In3[H1, H2, H3, ?], H3] { 112 | 113 | def extract[A](la: In3[H1, H2, H3, A]): Option[H3[A]] = la match { 114 | case In3l(_) => None 115 | case In3m(_) => None 116 | case In3r(r) => Some(r) 117 | } 118 | 119 | def build[A](ha: H3[A]): In3[H1, H2, H3, A] = In3r(ha) 120 | } 121 | 122 | 123 | implicit def appendLeft[L1[_] <: CopK[_], L2[_] <: CopK[_], H[_]]( 124 | implicit containsLeft: ContainsHK[L1, H] 125 | ): ContainsHK[AppendK[L1, L2, ?], H] = 126 | new ContainsHK[AppendK[L1, L2, ?], H] { 127 | 128 | def extract[A](la: AppendK[L1, L2, A]): Option[H[A]] = la match { 129 | case Aplk(l) => containsLeft.extract(l) 130 | case Aprk(_) => None 131 | } 132 | 133 | def build[A](ha: H[A]): AppendK[L1, L2, A] = Aplk(containsLeft.build(ha)) 134 | } 135 | 136 | } 137 | 138 | trait LowerContainsHK3 { 139 | 140 | implicit def appendRight[L1[_] <: CopK[_], L2[_] <: CopK[_], H[_]]( 141 | implicit containsRight: ContainsHK[L2, H] 142 | ): ContainsHK[AppendK[L1, L2, ?], H] = 143 | new ContainsHK[AppendK[L1, L2, ?], H] { 144 | 145 | def extract[A](la: AppendK[L1, L2, A]): Option[H[A]] = la match { 146 | case Aplk(_) => None 147 | case Aprk(r) => containsRight.extract(r) 148 | } 149 | 150 | def build[A](ha: H[A]): AppendK[L1, L2, A] = Aprk(containsRight.build(ha)) 151 | } 152 | 153 | // implicit def corec[H[_], K[_], L[_] <: CopK[_]]( 154 | // implicit next: ContainsHK[L, H] 155 | // ): ContainsHK[ConsK[K, L, ?], H] = 156 | // new ContainsHK[ConsK[K, L, ?], H] { 157 | 158 | // def extract[A](la: ConsK[K, L, A]): Option[H[A]] = la match { 159 | // case Inlk(h) => None 160 | // case Inrk(r) => next.extract(r) 161 | // } 162 | 163 | // def build[A](ha: H[A]): ConsK[K, L, A] = Inrk(next.build(ha)) 164 | // } 165 | 166 | } 167 | 168 | 169 | 170 | trait SubCop[L[_] <: CopK[_], L2[_] <: CopK[_]] { 171 | def apply[A](l: L[A]): L2[A] 172 | } 173 | 174 | object SubCop extends LowerSubCop { 175 | 176 | def apply[L[_] <: CopK[_], R[_] <: CopK[_]] 177 | (implicit subCop: SubCop[L, R]): SubCop[L, R] = subCop 178 | 179 | implicit def in1[H[_], L[_] <: CopK[_]]( 180 | implicit contains: ContainsHK[L, H] 181 | ) = new SubCop[In1[H, ?], L] { 182 | def apply[A](l: In1[H, A]): L[A] = contains.build(l.head) 183 | } 184 | 185 | implicit def in2[H1[_], H2[_], L[_] <: CopK[_]]( 186 | implicit contains1: ContainsHK[L, H1], contains2: ContainsHK[L, H2] 187 | ) = new SubCop[In2[H1, H2, ?], L] { 188 | def apply[A](l: In2[H1, H2, A]): L[A] = l match { 189 | case In2l(l) => contains1.build(l) 190 | case In2r(r) => contains2.build(r) 191 | } 192 | } 193 | 194 | implicit def in3[H1[_], H2[_], H3[_], L[_] <: CopK[_]]( 195 | implicit contains1: ContainsHK[L, H1], contains2: ContainsHK[L, H2], contains3: ContainsHK[L, H3] 196 | ) = new SubCop[In3[H1, H2, H3, ?], L] { 197 | def apply[A](l: In3[H1, H2, H3, A]): L[A] = l match { 198 | case In3l(l) => contains1.build(l) 199 | case In3m(m) => contains2.build(m) 200 | case In3r(r) => contains3.build(r) 201 | } 202 | } 203 | 204 | } 205 | 206 | trait LowerSubCop extends LowerSubCop2 { 207 | 208 | // implicit def single[H[_], L[_] <: CopK[_]]( 209 | // implicit contains: ContainsHK[L, H] 210 | // ) = new SubCop[ConsK[H, CNilK, ?], L] { 211 | // def apply[A](l: ConsK[H, CNilK, A]): L[A] = l match { 212 | // case Inlk(h) => contains.build(h) 213 | // case Inrk(_) => throw new RuntimeException("impossible case") 214 | // } 215 | // } 216 | 217 | implicit def appendkNil[L[_] <: CopK[_], L2[_] <: CopK[_]]( 218 | implicit subLeft: SubCop[L, L2] 219 | ) = new SubCop[AppendK[L, CNilK, ?], L2] { 220 | def apply[A](la: AppendK[L, CNilK, A]): L2[A] = la match { 221 | case Aplk(l) => subLeft(l) 222 | case Aprk(r) => throw new RuntimeException("impossible case") 223 | } 224 | } 225 | 226 | } 227 | 228 | trait LowerSubCop2 { 229 | 230 | implicit def appendk[L[_] <: CopK[_], R[_] <: CopK[_], L2[_] <: CopK[_]]( 231 | implicit subLeft: SubCop[L, L2], subRight: SubCop[R, L2] 232 | ) = new SubCop[AppendK[L, R, ?], L2] { 233 | def apply[A](la: AppendK[L, R, A]): L2[A] = la match { 234 | case Aplk(l) => subLeft(l) 235 | case Aprk(r) => subRight(r) 236 | } 237 | } 238 | 239 | // implicit def corec[H[_], L[_] <: CopK[_], L2[_] <: CopK[_]]( 240 | // implicit contains: ContainsHK[L2, H], next: SubCop[L, L2] 241 | // ) = new SubCop[ConsK[H, L, ?], L2] { 242 | // def apply[A](l: ConsK[H, L, A]): L2[A] = l match { 243 | // case Inlk(h) => contains.build(h) 244 | // case Inrk(r) => next(r) 245 | // } 246 | // } 247 | 248 | } 249 | 250 | // 251 | 252 | 253 | 254 | trait PrependHK[H[_], L[_] <: CopK[_]] { 255 | type Out[_] <: CopK[_] 256 | 257 | def apply[A](ha: L[A]): Out[A] 258 | def single[A](ha: H[A]): Out[A] 259 | 260 | def nat[R[_], A](out: Out[A], nat1: H ~> R, nat2: L ~> R): R[A] 261 | } 262 | 263 | object PrependHK extends PrependHKLower { 264 | 265 | def apply[H[_], L[_] <: CopK[_]] 266 | (implicit prep: PrependHK[H, L]): Aux[H, L, prep.Out] = prep 267 | 268 | type Aux[H[_], L[_] <: CopK[_], Out0[_] <: CopK[_]] = PrependHK[H, L] { type Out[t] = Out0[t] } 269 | 270 | implicit def in1[H1[_], H2[_]]: Aux[H1, In1[H2, ?], In2[H1, H2, ?]] = 271 | new PrependHK[H1, In1[H2, ?]] { 272 | type Out[t] = In2[H1, H2, t] 273 | 274 | def apply[A](c: In1[H2, A]): Out[A] = In2r(c.head) 275 | def single[A](ha: H1[A]): Out[A] = In2l(ha) 276 | 277 | def nat[R[_], A](out: In2[H1, H2, A], nat1: H1 ~> R, nat2: In1[H2, ?] ~> R): R[A] = out match { 278 | case In2l(l) => nat1(l) 279 | case In2r(r) => nat2(In1(r)) 280 | } 281 | } 282 | 283 | implicit def in2[H1[_], H2[_], H3[_]]: Aux[H1, In2[H2, H3, ?], In3[H1, H2, H3, ?]] = 284 | new PrependHK[H1, In2[H2, H3, ?]] { 285 | type Out[t] = In3[H1, H2, H3, t] 286 | 287 | def apply[A](c: In2[H2, H3, A]): Out[A] = c match { 288 | case In2l(left) => In3m(left) 289 | case In2r(right) => In3r(right) 290 | } 291 | 292 | def single[A](ha: H1[A]): Out[A] = In3l(ha) 293 | 294 | def nat[R[_], A](out: In3[H1, H2, H3, A], nat1: H1 ~> R, nat2: In2[H2, H3, ?] ~> R): R[A] = out match { 295 | case In3l(l) => nat1(l) 296 | case In3m(m) => nat2(In2l(m)) 297 | case In3r(r) => nat2(In2r(r)) 298 | } 299 | } 300 | 301 | implicit def in3[H1[_], H2[_], H3[_], H4[_]]: Aux[H1, In3[H2, H3, H4, ?], AppendK[In1[H1, ?], In3[H2, H3, H4, ?], ?]] = 302 | new PrependHK[H1, In3[H2, H3, H4, ?]] { 303 | type Out[t] = AppendK[In1[H1, ?], In3[H2, H3, H4, ?], t] 304 | 305 | def apply[A](c: In3[H2, H3, H4, A]): Out[A] = Aprk(c) 306 | 307 | def single[A](ha: H1[A]): Out[A] = Aplk(In1(ha)) 308 | 309 | def nat[R[_], A](out: AppendK[In1[H1, ?], In3[H2, H3, H4, ?], A], nat1: H1 ~> R, nat2: In3[H2, H3, H4, ?] ~> R): R[A] = out match { 310 | case Aplk(In1(l)) => nat1(l) 311 | case Aprk(m) => nat2(m) 312 | } 313 | } 314 | 315 | implicit def append1[H1[_], H2[_], R[_] <: CopK[_], C[_] <: CopK[_]]: Aux[H1, AppendK[In1[H2, ?], R, ?], AppendK[In2[H1, H2, ?], R, ?]] = 316 | new PrependHK[H1, AppendK[In1[H2, ?], R, ?]] { 317 | type Out[t] = AppendK[In2[H1, H2, ?], R, t] 318 | 319 | def apply[A](c: AppendK[In1[H2, ?], R, A]): Out[A] = c match { 320 | case Aplk(In1(l)) => Aplk(In2r(l)) 321 | case Aprk(r) => Aprk(r) 322 | } 323 | 324 | def single[A](ha: H1[A]): Out[A] = Aplk(In2l(ha)) 325 | 326 | def nat[RR[_], A](out: AppendK[In2[H1, H2, ?], R, A], nat1: H1 ~> RR, nat2: AppendK[In1[H2, ?], R, ?] ~> RR): RR[A] = out match { 327 | case Aplk(In2l(h1)) => nat1(h1) 328 | case Aplk(In2r(h2)) => nat2(Aplk(In1(h2))) 329 | case Aprk(r) => nat2(Aprk(r)) 330 | } 331 | } 332 | 333 | implicit def append2[H1[_], H2[_], H3[_], R[_] <: CopK[_], C[_] <: CopK[_]]: Aux[H1, AppendK[In2[H2, H3, ?], R, ?], AppendK[In3[H1, H2, H3, ?], R, ?]] = 334 | new PrependHK[H1, AppendK[In2[H2, H3, ?], R, ?]] { 335 | type Out[t] = AppendK[In3[H1, H2, H3, ?], R, t] 336 | 337 | def apply[A](c: AppendK[In2[H2, H3, ?], R, A]): Out[A] = c match { 338 | case Aplk(In2l(h2)) => Aplk(In3m(h2)) 339 | case Aplk(In2r(h3)) => Aplk(In3r(h3)) 340 | case Aprk(r) => Aprk(r) 341 | } 342 | 343 | def single[A](ha: H1[A]): Out[A] = Aplk(In3l(ha)) 344 | 345 | def nat[RR[_], A](out: AppendK[In3[H1, H2, H3, ?], R, A], nat1: H1 ~> RR, nat2: AppendK[In2[H2, H3, ?], R, ?] ~> RR): RR[A] = out match { 346 | case Aplk(In3l(h1)) => nat1(h1) 347 | case Aplk(In3m(h2)) => nat2(Aplk(In2l(h2))) 348 | case Aplk(In3r(h3)) => nat2(Aplk(In2r(h3))) 349 | case Aprk(r) => nat2(Aprk(r)) 350 | } 351 | } 352 | 353 | } 354 | 355 | trait PrependHKLower { 356 | 357 | 358 | implicit def append[H[_], L[_] <: CopK[_], R[_] <: CopK[_], C[_] <: CopK[_]]: PrependHK.Aux[H, AppendK[L, R, ?], AppendK[In1[H, ?], AppendK[L, R, ?], ?]] = 359 | new PrependHK[H, AppendK[L, R, ?]] { 360 | type Out[t] = AppendK[In1[H, ?], AppendK[L, R, ?], t] 361 | 362 | def apply[A](c: AppendK[L, R, A]): Out[A] = Aprk(c) 363 | 364 | def single[A](ha: H[A]): Out[A] = Aplk(In1(ha)) 365 | 366 | def nat[RR[_], A](out: AppendK[In1[H, ?], AppendK[L, R, ?], A], nat1: H ~> RR, nat2: AppendK[L, R, ?] ~> RR): RR[A] = out match { 367 | case Aplk(In1(h)) => nat1(h) 368 | case Aprk(r) => nat2(r) 369 | } 370 | } 371 | 372 | 373 | } 374 | 375 | 376 | trait Replace[C[_] <: CopK[_], F[_], G[_]] { 377 | 378 | type Out[_] <: CopK[_] 379 | 380 | def replace[A](c: C[A])(nat: F ~> G): Out[A] 381 | 382 | } 383 | 384 | object Replace extends ReplaceLower { 385 | 386 | type Aux[C[_] <: CopK[_], F[_], G[_], Out0[_] <: CopK[_]] = Replace[C, F, G] { type Out[t] = Out0[t] } 387 | 388 | implicit def in1[F[_], G[_]]: Replace.Aux[In1[F, ?], F, G, In1[G, ?]] = new Replace[In1[F, ?], F, G] { 389 | type Out[t] = In1[G, t] 390 | 391 | def replace[A](c: In1[F, A])(nat: F ~> G): In1[G, A] = In1(nat(c.head)) 392 | } 393 | 394 | implicit def in2l[F[_], G[_], H[_]]: Replace.Aux[In2[F, G, ?], F, H, In2[H, G, ?]] = new Replace[In2[F, G, ?], F, H] { 395 | type Out[t] = In2[H, G, t] 396 | 397 | def replace[A](c: In2[F, G, A])(nat: F ~> H): In2[H, G, A] = c match { 398 | case In2l(l) => In2l(nat(l)) 399 | case In2r(r) => In2r(r) 400 | } 401 | } 402 | 403 | implicit def in2r[F[_], G[_], H[_]]: Replace.Aux[In2[F, G, ?], G, H, In2[F, H, ?]] = new Replace[In2[F, G, ?], G, H] { 404 | type Out[t] = In2[F, H, t] 405 | 406 | def replace[A](c: In2[F, G, A])(nat: G ~> H): In2[F, H, A] = c match { 407 | case In2l(l) => In2l(l) 408 | case In2r(r) => In2r(nat(r)) 409 | } 410 | } 411 | 412 | implicit def in3l[F[_], G[_], H[_], I[_]]: Replace.Aux[In3[F, G, H, ?], F, I, In3[I, G, H, ?]] = new Replace[In3[F, G, H, ?], F, I] { 413 | type Out[t] = In3[I, G, H, t] 414 | 415 | def replace[A](c: In3[F, G, H, A])(nat: F ~> I): In3[I, G, H, A] = c match { 416 | case In3l(l) => In3l(nat(l)) 417 | case In3m(m) => In3m(m) 418 | case In3r(r) => In3r(r) 419 | } 420 | } 421 | 422 | implicit def in3m[F[_], G[_], H[_], I[_]]: Replace.Aux[In3[F, G, H, ?], G, I, In3[F, I, H, ?]] = new Replace[In3[F, G, H, ?], G, I] { 423 | type Out[t] = In3[F, I, H, t] 424 | 425 | def replace[A](c: In3[F, G, H, A])(nat: G ~> I): In3[F, I, H, A] = c match { 426 | case In3l(l) => In3l(l) 427 | case In3m(m) => In3m(nat(m)) 428 | case In3r(r) => In3r(r) 429 | } 430 | } 431 | 432 | implicit def in3r[F[_], G[_], H[_], I[_]]: Replace.Aux[In3[F, G, H, ?], H, I, In3[F, G, I, ?]] = new Replace[In3[F, G, H, ?], H, I] { 433 | type Out[t] = In3[F, G, I, t] 434 | 435 | def replace[A](c: In3[F, G, H, A])(nat: H ~> I): In3[F, G, I, A] = c match { 436 | case In3l(l) => In3l(l) 437 | case In3m(m) => In3m(m) 438 | case In3r(r) => In3r(nat(r)) 439 | } 440 | } 441 | 442 | implicit def appendl[L[_] <: CopK[_], R[_] <: CopK[_], F[_], G[_], O[_] <: CopK[_]]( 443 | implicit rep: Replace.Aux[L, F, G, O] 444 | ): Replace.Aux[AppendK[L, R, ?], F, G, AppendK[O, R, ?]] = new Replace[AppendK[L, R, ?], F, G] { 445 | type Out[t] = AppendK[O, R, t] 446 | 447 | def replace[A](c: AppendK[L, R, A])(nat: F ~> G) = c match { 448 | case Aplk(l) => Aplk(rep.replace(l)(nat)) 449 | case Aprk(r) => Aprk(r) 450 | } 451 | } 452 | } 453 | 454 | trait ReplaceLower { 455 | 456 | implicit def appendr[L[_] <: CopK[_], R[_] <: CopK[_], F[_], G[_], O[_] <: CopK[_]]( 457 | implicit rep: Replace.Aux[R, F, G, O] 458 | ): Replace.Aux[AppendK[L, R, ?], F, G, AppendK[L, O, ?]] = new Replace[AppendK[L, R, ?], F, G] { 459 | type Out[t] = AppendK[L, O, t] 460 | 461 | def replace[A](c: AppendK[L, R, A])(nat: F ~> G) = c match { 462 | case Aplk(l) => Aplk(l) 463 | case Aprk(r) => Aprk(rep.replace(r)(nat)) 464 | } 465 | } 466 | } 467 | 468 | // object CopAppend extends CopAppendLower { 469 | 470 | // def apply[L[_] <: CopK[_], R[_] <: CopK[_]](implicit copAppend: CopAppend[L, R]): CopAppend[L, R] = copAppend 471 | 472 | // type Aux[L[_] <: CopK[_], R[_] <: CopK[_], Out0[_] <: CopK[_]] = CopAppend[L, R] { 473 | // type Out[t] = Out0[t] 474 | // } 475 | 476 | // implicit def nil[H1[_], H2[_], R2[_] <: CopK[_]]: CopAppend.Aux[AppendK[In1[H1, ?], CNilK, ?], AppendK[In1[H2, ?], R2, ?], AppendK[In1[H1, ?], AppendK[In1[H2, ?], R2, ?], ?]] = 477 | // new CopAppend[AppendK[In1[H1, ?], CNilK, ?], AppendK[In1[H2, ?], R2, ?]] { 478 | // type Out[t] = AppendK[In1[H1, ?], AppendK[In1[H2, ?], R2, ?], t] 479 | 480 | // def left[A](l: AppendK[In1[H1, ?], CNilK, A]): Out[A] = l match { 481 | // case Aplk(in1) => Aplk(in1) 482 | // case Aprk(_) => throw new RuntimeException("impossible case") 483 | // } 484 | 485 | // def right[A](l: AppendK[In1[H2, ?], R2, A]): Out[A] = l match { 486 | // case Aplk(in2) => Aprk(Aplk(in2)) 487 | // case Aprk(r2) => Aprk(Aprk(r2)) 488 | // } 489 | 490 | // def extract[A](o: Out[A]): Xor[AppendK[In1[H1, ?], CNilK, A], AppendK[In1[H2, ?], R2, A]] = o match { 491 | // case Aplk(In1(h1)) => Xor.left(Aplk(In1(h1))) 492 | // case Aprk(Aplk(In1(h2))) => Xor.right(Aplk(In1(h2))) 493 | // case Aprk(Aprk(r2)) => Xor.right(Aprk(r2)) 494 | // case _ => throw new RuntimeException("impossible case") 495 | // } 496 | // } 497 | // } 498 | 499 | // trait CopAppendLower { 500 | // implicit def rec[H1[_], R1[_] <: CopK[_], R2[_] <: CopK[_], O[_] <: CopK[_]]( 501 | // implicit next: CopAppend.Aux[R1, R2, O] 502 | // ): CopAppend.Aux[AppendK[In1[H1, ?], R1, ?], R2, AppendK[In1[H1, ?], O, ?]] = 503 | // new CopAppend[AppendK[In1[H1, ?], R1, ?], R2] { 504 | // type Out[t] = AppendK[In1[H1, ?], O, t] 505 | 506 | // def left[A](l: AppendK[In1[H1, ?], R1, A]): Out[A] = l match { 507 | // case Aplk(in1) => Aplk(in1) 508 | // case Aprk(r1) => Aprk(next.left(r1)) 509 | // } 510 | 511 | // def right[A](r2: R2[A]): Out[A] = Aprk(next.right(r2)) 512 | 513 | // def extract[A](o: Out[A]): Xor[AppendK[In1[H1, ?], R1, A], R2[A]] = o match { 514 | // case Aplk(In1(h1)) => Xor.left(Aplk(In1(h1))) 515 | // case Aprk(o) => next.extract(o) match { 516 | // case Xor.Left(r1) => Xor.left(Aprk(r1)) 517 | // case Xor.Right(r2) => Xor.right(r2) 518 | // } 519 | // } 520 | // } 521 | // } 522 | 523 | // trait CopIso[L[_] <: CopK[_], R[_] <: CopK[_]] { 524 | // def to[A](l: L[A]): R[A] 525 | // def from[A](r: R[A]): L[A] 526 | // } 527 | 528 | // object CopIso extends CopIsoLower { 529 | 530 | // def apply[L[_] <: CopK[_], R[_] <: CopK[_]](implicit copIso: CopIso[L, R]): CopIso[L, R] = copIso 531 | 532 | // implicit def in1[H[_]] = new CopIso[In1[H, ?], AppendK[In1[H, ?], CNilK, ?]] { 533 | // def to[A](l: In1[H, A]): AppendK[In1[H, ?], CNilK, A] = Aplk(l) 534 | // def from[A](r: AppendK[In1[H, ?], CNilK, A]): In1[H, A] = r match { 535 | // case Aplk(l) => l 536 | // case Aprk(_) => throw new RuntimeException("impossible case") 537 | // } 538 | // } 539 | 540 | // implicit def in2[H1[_], H2[_]] = new CopIso[In2[H1, H2, ?], AppendK[In1[H1, ?], AppendK[In1[H2, ?], CNilK, ?], ?]] { 541 | // def to[A](l: In2[H1, H2, A]): AppendK[In1[H1, ?], AppendK[In1[H2, ?], CNilK, ?], A] = l match { 542 | // case In2l(l) => Aplk(In1(l)) 543 | // case In2r(r) => Aprk(Aplk(In1(r))) 544 | // } 545 | // def from[A](r: AppendK[In1[H1, ?], AppendK[In1[H2, ?], CNilK, ?], A]): In2[H1, H2, A] = r match { 546 | // case Aplk(In1(l)) => In2l(l) 547 | // case Aprk(Aplk(In1(r))) => In2r(r) 548 | // case _ => throw new RuntimeException("impossible case") 549 | // } 550 | // } 551 | 552 | // implicit def in3[H1[_], H2[_], H3[_]] = new CopIso[In3[H1, H2, H3, ?], AppendK[In1[H1, ?], AppendK[In1[H2, ?], AppendK[In1[H3, ?], CNilK, ?], ?], ?]] { 553 | // def to[A](l: In3[H1, H2, H3, A]): AppendK[In1[H1, ?], AppendK[In1[H2, ?], AppendK[In1[H3, ?], CNilK, ?], ?], A] = l match { 554 | // case In3l(l) => Aplk(In1(l)) 555 | // case In3m(m) => Aprk(Aplk(In1(m))) 556 | // case In3r(r) => Aprk(Aprk(Aplk(In1(r)))) 557 | // } 558 | // def from[A](r: AppendK[In1[H1, ?], AppendK[In1[H2, ?], AppendK[In1[H3, ?], CNilK, ?], ?], A]): In3[H1, H2, H3, A] = r match { 559 | // case Aplk(In1(l)) => In3l(l) 560 | // case Aprk(Aplk(In1(m))) => In3m(m) 561 | // case Aprk(Aprk(Aplk(In1(r)))) => In3r(r) 562 | // case _ => throw new RuntimeException("impossible case") 563 | // } 564 | // } 565 | 566 | // } 567 | 568 | // trait CopIsoLower { 569 | // implicit def rec[L[_] <: CopK[_], R[_] <: CopK[_], OL[_] <: CopK[_], OR[_] <: CopK[_], O[_] <: CopK[_]]( 570 | // implicit 571 | // leftIso: CopIso[L, OL] 572 | // , rightIso: CopIso[R, OR] 573 | // , ap: CopAppend.Aux[OL, OR, O] 574 | // ) = new CopIso[AppendK[L, R, ?], O] { 575 | 576 | // def to[A](l: AppendK[L, R, A]): O[A] = l match { 577 | // case Aplk(l) => ap.left(leftIso.to(l)) 578 | // case Aprk(r) => ap.right(rightIso.to(r)) 579 | // } 580 | // def from[A](o: O[A]): AppendK[L, R, A] = ap.extract(o) match { 581 | // case Xor.Left(l) => Aplk(leftIso.from(l)) 582 | // case Xor.Right(r) => Aprk(rightIso.from(r)) 583 | // } 584 | // } 585 | // } 586 | 587 | // trait CopAppend[L[_] <: CopK[_], R[_] <: CopK[_]] { 588 | // type Out[_] <: CopK[_] 589 | 590 | // def left[A](l: L[A]): Out[A] 591 | // def right[A](l: R[A]): Out[A] 592 | // def extract[A](o: Out[A]): Xor[L[A], R[A]] 593 | // } 594 | 595 | // trait MergeOneRightHK[L[_] <: CopK[_], H[_]] { 596 | // type Out[_] <: CopK[_] 597 | 598 | // def apply[A](ha: L[A]): Out[A] 599 | // def single[A](ha: H[A]): Out[A] 600 | // } 601 | 602 | // object MergeOneRightHK extends LowerMergeOneRightHK { 603 | 604 | // def apply[L[_] <: CopK[_], H[_]] 605 | // (implicit mergeOneRightHK: MergeOneRightHK[L, H]): Aux[L, H, mergeOneRightHK.Out] = mergeOneRightHK 606 | 607 | // type Aux[L[_] <: CopK[_], H[_], Out0[_] <: CopK[_]] = MergeOneRightHK[L, H] { type Out[t] = Out0[t] } 608 | 609 | // implicit def singleton[H[_], G[_]]: Aux[ConsK[H, CNilK, ?], G, ConsK[H, ConsK[G, CNilK, ?], ?]] = 610 | // new MergeOneRightHK[ConsK[H, CNilK, ?], G] { 611 | // type Out[t] = ConsK[H, ConsK[G, CNilK, ?], t] 612 | 613 | // def apply[A](c: ConsK[H, CNilK, A]): Out[A] = c match { 614 | // case Inlk(h) => Inlk(h) 615 | // case Inrk(t) => Inrk(Inrk(t)) 616 | // } 617 | 618 | // def single[A](ga: G[A]): Out[A] = Inrk(Inlk(ga)) 619 | // } 620 | 621 | // } 622 | 623 | // trait LowerMergeOneRightHK extends LowerMergeOneRightHK2 { 624 | 625 | // implicit def contains[H[_], T[_] <: CopK[_]] 626 | // (implicit 627 | // contains: ContainsHK[T, H] 628 | // ): MergeOneRightHK.Aux[T, H, T] = 629 | // new MergeOneRightHK[T, H] { 630 | // type Out[t] = T[t] 631 | 632 | // def apply[A](c: T[A]): Out[A] = c 633 | 634 | // def single[A](ha: H[A]): Out[A] = contains.build(ha) 635 | // } 636 | 637 | // } 638 | 639 | // trait LowerMergeOneRightHK2 { 640 | // implicit def corec[H[_], K[_], T[_] <: CopK[_], T2[_] <: CopK[_]] 641 | // (implicit next: MergeOneRightHK.Aux[T, H, T2]): MergeOneRightHK.Aux[ConsK[K, T, ?], H, ConsK[K, T2, ?]] = 642 | // new MergeOneRightHK[ConsK[K, T, ?], H] { 643 | // type Out[t] = ConsK[K, T2, t] 644 | 645 | // def apply[A](c: ConsK[K, T, A]): Out[A] = c match { 646 | // case Inlk(h) => Inlk(h) 647 | // case Inrk(t) => Inrk(next(t)) 648 | // } 649 | 650 | // def single[A](ha: H[A]): Out[A] = Inrk(next.single(ha)) 651 | // } 652 | // } 653 | 654 | // trait MergeCopHK[L[_] <: CopK[_], R[_] <: CopK[_]] { 655 | // type Out[_] <: CopK[_] 656 | 657 | // def fromLeft[A](la: L[A]): Out[A] 658 | 659 | // def fromRight[A](ra: R[A]): Out[A] 660 | // } 661 | 662 | 663 | // object MergeCopHK extends LowerMergeCopHK { 664 | 665 | // def apply[L[_] <: CopK[_], R[_] <: CopK[_]] 666 | // (implicit mergeCopHK: MergeCopHK[L, R]): Aux[L, R, mergeCopHK.Out] = mergeCopHK 667 | 668 | // type Aux[L[_] <: CopK[_], R[_] <: CopK[_], Out0[_] <: CopK[_]] = MergeCopHK[L, R] { type Out[t] = Out0[t] } 669 | 670 | // implicit def one[L[_] <: CopK[_], H[_], LH[_] <: CopK[_]]( 671 | // implicit mergeOne: MergeOneRightHK.Aux[L, H, LH] 672 | // ): Aux[L, ConsK[H, CNilK, ?], LH] = 673 | // new MergeCopHK[L, ConsK[H, CNilK, ?]] { 674 | // type Out[t] = LH[t] 675 | 676 | // def fromLeft[A](la: L[A]): Out[A] = mergeOne(la) 677 | 678 | // def fromRight[A](ra: ConsK[H, CNilK, A]): Out[A] = ra match { 679 | // case Inlk(ha) => mergeOne.single(ha) 680 | // case Inrk(_) => throw new RuntimeException("impossible case") 681 | // } 682 | // } 683 | // } 684 | 685 | // trait LowerMergeCopHK { 686 | // implicit def corec[L[_] <: CopK[_], H[_], LH[_] <: CopK[_], T[_] <: CopK[_], T2[_] <: CopK[_]]( 687 | // implicit mergeOne: MergeOneRightHK.Aux[L, H, LH], next: MergeCopHK.Aux[LH, T, T2] 688 | // ): MergeCopHK.Aux[L, ConsK[H, T, ?], T2] = 689 | // new MergeCopHK[L, ConsK[H, T, ?]] { 690 | // type Out[t] = T2[t] 691 | 692 | // def fromLeft[A](la: L[A]): Out[A] = next.fromLeft(mergeOne(la)) 693 | // def fromRight[A](ra: ConsK[H, T, A]): Out[A] = ra match { 694 | // case Inlk(ha) => next.fromLeft(mergeOne.single(ha)) 695 | // case Inrk(ta) => next.fromRight(ta) 696 | // } 697 | // } 698 | // } 699 | 700 | 701 | 702 | /*trait ContainsHKLub[L[_] <: CopK[_], H[_]] extends Serializable { 703 | type R[_] <: CopK[_] 704 | 705 | type Lub[_] 706 | 707 | def extract[A](la: L[A]): Option[Lub[A]] 708 | def build[A](ha: H[A]): L[A] 709 | } 710 | 711 | 712 | object ContainsHKLub extends LowerContainsHKLub { 713 | 714 | type Aux[L[_] <: CopK[_], H[_], R0[_] <: CopK[_], Lub0[_]] = 715 | ContainsHKLub[L, H] { type R[t] = R0[t]; type Lub[t] = Lub0[t] } 716 | 717 | def apply[L[_] <: CopK[_], H[_]] 718 | (implicit containsHK: ContainsHKLub[L, H]): Aux[L, H, containsHK.R, containsHK.Lub] = containsHK 719 | 720 | implicit def head[H[_], K[_], L[_] <: CopK[_]]( 721 | implicit ev: H[_] <:< K[_] 722 | ): ContainsHKLub.Aux[ConsK[K, L, ?], H, L, K] = 723 | new ContainsHKLub[ConsK[K, L, ?], H] { 724 | type R[t] = L[t] 725 | type Lub[t] = K[t] 726 | 727 | def extract[A](la: ConsK[K, L, A]): Option[K[A]] = la match { 728 | case Inlk(h) => Some(h) 729 | case Inrk(_) => None 730 | } 731 | 732 | def build[A](ha: H[A]): ConsK[K, L, A] = Inlk(ha.asInstanceOf[K[A]]) 733 | } 734 | 735 | } 736 | 737 | 738 | trait LowerContainsHKLub { 739 | 740 | implicit def corec[H[_], K[_], L[_] <: CopK[_], RT[_] <: CopK[_], RTLub[_]]( 741 | implicit next: ContainsHKLub.Aux[L, H, RT, RTLub] 742 | ): ContainsHKLub.Aux[ConsK[K, L, ?], H, ConsK[K, RT, ?], RTLub] = 743 | new ContainsHKLub[ConsK[K, L, ?], H] { 744 | type R[t] = ConsK[K, RT, t] 745 | type Lub[t] = RTLub[t] 746 | 747 | def extract[A](la: ConsK[K, L, A]): Option[RTLub[A]] = la match { 748 | case Inlk(h) => None 749 | case Inrk(r) => next.extract(r) 750 | } 751 | 752 | def build[A](ha: H[A]): ConsK[K, L, A] = Inrk(next.build(ha)) 753 | } 754 | }*/ 755 | 756 | 757 | 758 | --------------------------------------------------------------------------------