2015-06-24 11 views
6

Czy to możliwe, aby w jakiś sposób Marshall funkcja częściowa (załóżmy, to zawsze zawiera tylko jeden przypadek) do czegoś czytelny dla człowieka?Scala Pattern Matching dość drukowane

Załóżmy, że mamy kolekcję typu Dowolny (komunikaty: Lista [Any]) i numer PartialFuntion [Any, T] zdefiniowany za pomocą bloku dopasowywania wzorców.

case object R1 
case object R2 
case object R3 

val pm1: PartialFunction[Any, Any] = { 
    case "foo" => R1 
} 

val pm2: PartialFunction[Any, Any] = { 
    case x: Int if x > 10 => R2 
} 

val pm3: PartialFunction[Any, Any] = { 
    case x: Boolean => R3 
} 

val messages: List[Any] = List("foo", 20) 
val functions = List(pm1, pm2) 

wtedy możemy znaleźć wszystkie wiadomości pasujące świadczonych PFS i aplikacji powiązanych

val found: List[Option[Any]] = functions map { f => 
    messages.find(f.isDefined).map(f) 
} 

ale co jeśli ja potrzeba wynikająca mapę „czego można oczekiwać” do „co mam” w czytelny dla człowieka formularz (do logowania). Powiedz,

Czy to możliwe? Niektóre makro/meta działa?

+0

Neat pomysł. W ogóle muszę powiedzieć coś więcej ... Oczywiście, alternatywą są inne efekty uboczne. –

Odpowiedz

1

Dzięki za odpowiedzi. Używanie Macro jest interesującym wyborem. Ale opcjonalnie rozwiązaniem może być użycie nazwanych funkcji częściowych. Chodzi o to, aby nazwa funkcji, więc na wyjściu można zobaczyć nazwę funkcji zamiast kodu źródłowego.

object PartialFunctions { 

    type FN[Result] = PartialFunction[Any, Result] 

    case class NamedPartialFunction[A,B](name: String)(pf: PartialFunction[A, B]) extends PartialFunction[A,B] { 
    override def isDefinedAt(x: A): Boolean = pf.isDefinedAt(x) 
    override def apply(x: A): B = pf.apply(x) 
    override def toString(): String = s"matching($name)" 
    } 

    implicit class Named(val name: String) extends AnyVal { 
    def %[A,B](pf: PartialFunction[A,B]) = new NamedPartialFunction[A, B](name)(pf) 
    } 

} 

Tak więc można go używać w następujący sposób

import PartialFunctions._ 

val pm1: PartialFunction[Any, Any] = "\"foo\"" % { 
    case "foo" => R1 
} 

val pm2: PartialFunction[Any, Any] = "_: Int > 10" % { 
    case x: Int if x > 10 => R2 
} 

val pm3: PartialFunction[Any, Any] = "_: Boolean" % { 
    case x: Boolean => R3 
} 

val messages: List[Any] = List("foo", 20) 
val functions = List(pm1, pm2) 

val found: List[Option[(String, Any)]] = functions map { case f: NamedPartialFunction => 
    messages.find(f.isDefined).map(m => (f.name, f(m)) 
} 
2

Nie ma niczego w czasie wykonywania, które ładnie wydrukuje skompilowany kod.

Możesz napisać makro, które wydrukuje kod źródłowy drzewa i użyje tego? Większość samouczków makr rozpoczyna się od makra do drukowania kodu źródłowego - patrz np. http://www.warski.org/blog/2012/12/starting-with-scala-macros-a-short-tutorial/

Może:

// Given a partial function "pf", return the source code for pf 
// as a string as well as the compiled, runnable function itself 
def functionAndSource(pf: PartialFunction[Any, Any]): (String, PartialFunction[Any, Any]) = macro functionAndSourceImpl 

def functionAndSourceImpl ... 

val pm1: (String, PartialFunction[Any, Any]) = functionAndSource { 
    case "foo" => R1 
} 

To nie jest kiedykolwiek będzie to łatwe ani przyjemne w Scala. Scala to nie Lisp lub Ruby: jest to język skompilowany i nie jest zoptymalizowany pod kątem refleksji nad samym kodem.