Как указать тип, введенный в совпадении класса с независимым параметром типа - PullRequest
2 голосов
/ 25 октября 2019

Я следовал разговору Рунара Бьярнасона о свободных монадах: http://functionaltalks.org/2014/11/23/runar-oli-bjarnason-free-monad/

У меня есть следующий фрагмент кода из его первоначального примера (я использовал название Continuation вместо Bind и Box вместо F -Сейчас они мне нравятся больше):

object TestFreeMonads
{
  sealed trait Interact[A]

  case class Ask(prompt: String) extends Interact[String]
  case class Tell(msg: String) extends Interact[Unit]


  sealed trait Free[Box[_], A] {
    def flatMap[B](f: A => Free[Box, B]): Free[Box, B] =
      this match {
        case Return(a) => f(a)
        case Continuation(v, cont ) => Continuation(v, cont andThen (_ flatMap f)   )
//      The following line does not compile: missing parameter type for expanded function ((<x$1: error>) => cont(x$1).flatMap(f))
//        case Continuation(v, cont ) => Continuation(v,  cont(_).flatMap(f) )
//      This line does compile:
//        case Continuation(v, cont ) => Continuation[Box, Any, B](v, cont(_).flatMap(f) )
      }

    def map[B](f: A => B): Free[Box, B] = flatMap(a => Return(f(a)))
  }

  case class Return[Box[_], A](a: A) extends Free[Box, A]
  case class Continuation[Box[_], I, A](v: Box[I], cont: I => Free[Box, A]) extends Free[Box, A]

  def lift[Box[_], A](v: Box[A]): Free[Box, A] = Continuation(v, (a: A) => Return(a))

  implicit def liftInteract[A](v: Interact[A]) : Free[Interact, A] = lift(v)

  def prog: Free[Interact, Unit]  = {
    for {
      first <- Ask("First Name")
      last <- Ask("Last Name")
      _ <- Tell(s"Hello, $first $last")
    } yield ()
  }

}

Я не понимаю, почему эта строка компилируется: case Continuation(v, cont ) => Continuation(v, cont andThen (_ flatMap f) ), но не эта: case Continuation(v, cont ) => Continuation(v, cont(_).flatMap(f) ).

Третья строка case Continuation(v, cont ) => Continuation[Box, Any, B](v, cont(_).flatMap(f) ) также компилируется, но это довольно многословно, и я использовал Any в качестве значения для параметра типа I, что, на мой взгляд, сомнительно. В идеале я должен как-то объявить тип v и использовать его, но это не представляется возможным.

В конечном итоге v имеет тип I, но он как бы скрыт.

Я использовалscala 2.13.1:

...
scalaVersion := "2.13.1"

scalacOptions += "-feature"
scalacOptions += "-language:implicitConversions"
...

1 Ответ

4 голосов
/ 25 октября 2019

Попробуйте связать переменную типа i (в нижнем регистре)

case Continuation(v, cont: Function1[i, _]) => Continuation(v, cont(_: i).flatMap(f))

Также вы можете использовать тип шаблона

case c: Continuation[Box, i, A] => Continuation(c.v, c.cont(_: i).flatMap(f))
...