开发者

scala: function recursively returns a function object, how to overcome illegal cyclic reference?

开发者 https://www.devze.com 2023-03-17 09:46 出处:网络
i have a class with a method that returns a function object. the requirements are that the method is arity 0 and its return type is an Option of a Function0 - whose return type is the original return

i have a class with a method that returns a function object. the requirements are that the method is arity 0 and its return type is an Option of a Function0 - whose return type is the original return type. for example:

class MyClass {
  def f(): Option[Function[A]] = Some(g _)
  def g(): Option[Function[A]] = Some(h _)
  ... goes on and on, eventually returns Some(z _) ...
  def z(): Option[Function[A]] = None
}

Due to the recursion, the issue is that the type A is defined as:

type A = Option[Function开发者_运维知识库0[A]]

but since cyclic references are not allowed, it produces the error:

illegal cyclic reference involving type A

i obviously want to avoid defining a different return type for each of the methods, but having a unified return type doesn't seem possible due to the cycle. is there any way to do this? thanks!


This is not supported by Scala type definitions. See How to define a cyclic type definition?

You can accomplish this with a class instead of a type, although you would have to define your own Option-like class. An example is below (with monadic methods omitted). Also, see this mailing list discussion: http://www.scala-lang.org/node/2541

sealed trait OptionalFunction extends (() => OptionalFunction) {
  def get: (() => OptionalFunction)
}
case class SomeFunction(fn: () => OptionalFunction) extends OptionalFunction {
  def apply() = fn()
  def get = fn
}
case object NoFunction extends OptionalFunction {
  def apply() = this
  def get = throw new NoSuchElementException
}

class MyClass {
  type A = OptionalFunction
  def f(): A = SomeFunction(g _)
  def g(): A = SomeFunction(h _)
  def h(): A = SomeFunction(() => { println("At the end!"); i })
  def i(): A = NoFunction
}

scala> new MyClass().f()()()()
At the end!
res0: OptionalFunction[Unit] = <function0>


I'm not sure if this is what you're looking for, but many of these edge-cases can be worked around with explicitly using objects:

abstract class F extends Function0[F]
val p = new F {
    def apply() = { println("hi"); this }
}
>> defined class F
>> p: $anon forSome { type $anon <: F{def apply(): $anon} } =     
p()    
>> hi
>> res2: $anon =     
p()()    
>> hi
>> hi
>> res3: $anon = 

Happy coding.

0

精彩评论

暂无评论...
验证码 换一张
取 消