Давайте этот код:Как создать настраиваемый оператор, имитирующий точку (без круглых скобок)?
scala> case class Num(n:Int){def inc = Num(n+1)}
defined class Num
scala> implicit class Pipe(n:Num){ def | = n }
defined class Pipe
Это работает:
scala> (Num(0) |) inc
res7: Num = Num(1)
Но можно как-то (возможно, implicits или макросы?) Делают Scala для запуска образца, приведенную ниже в той же образом, как код с круглыми скобками без изменения Num
класс?
scala> Num(0) | inc
<console>:11: error: Num does not take parameters
Num(0) | inc
^
Wanted результат:
scala> Num(0) | inc | inc
res8: Num = Num(2)
EDIT:
Вот код, который гораздо ближе к реальной вещи. Надеюсь, это более понятно.
object ApplyTroubles2 extends App {
import GrepOption.GrepOption
abstract class Builder {
var parent: Builder = null
def getOutput: String
def append(ch: Builder) = { ch.parent = this; ch }
def echo(s: String) = append(new Echo(s))
def wc() = append(new Wc())
def grep(s: String, opts: Set[GrepOption]) = append(new Grep(s, opts))
def grep(s: String) = append(new Grep(s))
}
object MainBuilder extends Builder {
def getOutput: String = ""
override def append(ch: Builder): Builder = ch
}
class Echo(data: String) extends Builder {
def getOutput = data
}
class Wc() extends Builder {
def getOutput = parent.getOutput.size.toString
}
class Grep(var pattern: String, options: Set[GrepOption]) extends Builder {
def this(pattern: String) = this(pattern, Set.empty)
val isCaseInsensitive = options.contains(GrepOption.CASE_INSENSITIVE)
if (isCaseInsensitive) pattern = pattern.toLowerCase
def getOutput = {
val input = if (isCaseInsensitive) parent.getOutput.toLowerCase else parent.getOutput
if (input.contains(pattern)) input
else ""
}
}
object GrepOption extends Enumeration {
type GrepOption = Value
val CASE_INSENSITIVE = Value
}
object BuilderPimps {
// val wc: Builder => Builder = x => x.wc()
// def echo(msg: String): Builder => Builder = x => x.echo(msg)
}
implicit class BuilderPimps(b: Builder) {
// as suggested in one answer, should solve calling an apply method
// def |(fn: Builder => Builder): Builder = fn(b)
def | : Builder = b
def getStringOutput: String = b.getOutput
def >> : String = getStringOutput
}
import MainBuilder._
// working
println(echo("xxx").wc().getOutput)
println(echo("str") getStringOutput)
println((echo("y") |) wc() getStringOutput)
println(((((echo("y") |) echo ("zz")) |) wc()) >>)
println(((echo("abc") |) grep ("b")) >>)
println((echo("aBc") |) grep("AbC", Set(GrepOption.CASE_INSENSITIVE)) getStringOutput)
// not working
println((echo("yyyy") | wc()) getStringOutput)
println(echo("yyyy") | wc() getStringOutput)
println((echo("y")|) grep("y") >>)
println(echo("x") | grep("x") | wc() >>)
}
Я понимаю, что разыскиваемый оператор не добавляет дополнительную ценность с точки зрения функциональности, это должно быть просто синтаксический сахар, чтобы сделать вещи выглядят лучше (в данном случае я пытаюсь имитировать трубы оболочки).
Только намек, если вы используете свободные функции много, то вообще 'труба вперед' оператор a'la F # может стать полезным: 'неявного класса ForwardPipe [T, U] (Arg: T) {def |> (f: T => U) = f (arg)} ' –
Да - это хорошо! –
Спасибо за сообщение. Но я не уверен, что смогу это использовать. Первая проблема заключается в том, что я понятия не имею, как я могу расширить это решение для принятия параметров (он должен имитировать «точку», но, возможно, частично применяемые функции могли бы сделать трюк?). Также я надеялся на более общее решение - класс, который я хотел сутенер, имеет десятки (возможно, hundread) методов, это означало бы, что мне придется создавать обертки для каждого метода ... – monnef