All Downloads are FREE. Search and download functionalities are using the official Maven repository.

quasar.fp.free.Interpreter.scala Maven / Gradle / Ivy

There is a newer version: 28.1.6
Show newest version
/*
 * Copyright 2014–2016 SlamData Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package quasar.fp.free

import quasar.Predef._
import quasar.fp._

import scalaz._
import scalaz.stream.Process

/** Provides a range of natural transformations that can be derived from the natural transformation of a term
  * of an algebra into the desired `Monad`
  * @param interpretTerm A natural transformation from the Algebra into the desired `Monad` from which
  *                      many other natural transformations can be derived
  * @tparam F The type of the `Functor` that represents the algebra to be interpreted
  * @tparam M The `Monad` into which to translate the `Free` Algebra
  */
class Interpreter[F[_]: Functor, M[_]: Monad](val interpretTerm: F ~> M) {
  type Program[A] = Free[F,A]

  def interpret: Program ~> M =
    hoistFree(interpretTerm)

  def interpretT[T[_[_],_]: Hoist]: T[Program,?] ~> T[M,?] =
    Hoist[T].hoist[Program,M](interpret)

  def interpretT2[T1[_[_],_]: Hoist, T2[_[_],_]: Hoist]: T1[T2[Program,?],?] ~> T1[T2[M,?],?] =
    Hoist[T1].hoist[T2[Program,?],T2[M,?]](interpretT[T2])(Hoist[T2].apply[Program])

  def interpretT3[T1[_[_],_]: Hoist, T2[_[_],_]: Hoist, T3[_[_],_]: Hoist]: T1[T2[T3[Program,?],?],?] ~> T1[T2[T3[M,?],?],?] =
    Hoist[T1].hoist[T2[T3[Program,?],?], T2[T3[M,?],?]](interpretT2[T2,T3])(Hoist[T2].apply[T3[Program,?]](Hoist[T3].apply[Program]))

  def runLog[A](p: Process[Program,A])(implicit catchable: Catchable[M]): M[Vector[A]] =
    p.translate(interpret).runLog

  def runLogT[T[_[_],_]:Hoist,A](p: Process[T[Program,?],A])(implicit catchable: Catchable[T[M,?]]): T[M,Vector[A]] = {
    type ResultT[A] = T[M,A]
    val monadR: Monad[ResultT] = Hoist[T].apply
    p.translate[T[M,?]](interpretT[T]).runLog[ResultT,A](monadR, catchable)
  }

  def runLogT2[T1[_[_],_]: Hoist, T2[_[_],_]: Hoist,A](p: Process[T1[T2[Program,?],?],A])(implicit catchable: Catchable[T1[T2[M,?],?]]): T1[T2[M,?],Vector[A]] = {
    type ResultT[A] = T1[T2[M,?],A]
    val monadR: Monad[ResultT] = Hoist[T1].apply[T2[M,?]](Hoist[T2].apply)
    p.translate[ResultT](interpretT2[T1,T2]).runLog[ResultT,A](monadR,catchable)
  }

  def runLogT3[T1[_[_],_]:Hoist, T2[_[_],_]: Hoist, T3[_[_],_]: Hoist ,A](p: Process[T1[T2[T3[Program,?],?],?],A])(implicit catchable: Catchable[T1[T2[T3[M,?],?],?]])
  : T1[T2[T3[M,?],?],Vector[A]] = {
    type ResultT[A] = T1[T2[T3[M,?],?],A]
    val monadR: Monad[ResultT] = Hoist[T1].apply[T2[T3[M,?],?]](Hoist[T2].apply[T3[M,?]](Hoist[T3].apply))
    p.translate[ResultT](interpretT3[T1,T2,T3]).runLog[ResultT,A](monadR,catchable)
  }
}

/** Extends Interpreter to provide a version with better type inference for commonly used `MonadTrans`
  * @param interpretTerm A natural transformation from the Algebra into the desired `Monad` from which
  *                      many other natural transformations can be derived
  * @tparam F The type of the `Functor` that represents the algebra to be interpreted
  * @tparam M The `Monad` into which to translate the `Free` Algebra
  */
// https://github.com/puffnfresh/wartremover/issues/149
@SuppressWarnings(Array("org.brianmckenna.wartremover.warts.NonUnitStatements"))
class SpecializedInterpreter[F[_]: Functor, M[_]: Monad](interpretTerm: F ~> M) extends Interpreter(interpretTerm) {
  def runLog[E,A](p: Process[EitherT[Program,E,?],A])(implicit catchable: Catchable[M]): EitherT[M,E,Vector[A]] = {
    type T[Program[_],A] = EitherT[Program,E,A]
    runLogT[T,A](p)
  }
  def runLog[E,L:Monoid,A](p: Process[EitherT[WriterT[Program,L,?],E,?],A])(implicit catchable: Catchable[M]): EitherT[WriterT[M,L,?],E,Vector[A]] = {
    type T1[M[_],A] = EitherT[M,E,A]
    type T2[M[_],A] = WriterT[M,L,A]
    type WriterResult[A] = T2[M,A]
    type ResultT[A] = T1[T2[M,?],A]
    val catchableR: Catchable[ResultT] = eitherTCatchable[WriterResult,E](writerTCatchable[M,L], WriterT.writerTFunctor[M,L])
    runLogT2[T1,T2,A](p)(Hoist[T1],Hoist[T2],catchableR)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy