में नेस्टेड कक्षाओं के लिए लेखन प्रकार वर्ग उदाहरण this recent Stack Overflow question में, लेखक किसी प्रकार के पार्सर्स की एक सूची को एक पार्सर में बदलना चाहता था जो उस प्रकार की सूचियों को लौटाता है। हम अनुप्रयोगी functors के लिए Scalaz के sequence
के साथ ऐसा करने कल्पना कर सकते हैं:स्कैला
import scala.util.parsing.combinator._
import scalaz._
import Scalaz._
object parser extends RegexParsers {
val parsers = List(1, 2, 3).map(repN(_, """\d+""".r))
def apply(s: String) = parseAll(parsers.sequence, s)
}
यहाँ हम तीन पारसर्स कि पूर्णांकों की सूची लौट सकते हैं और यह एक पार्सर कि पूर्णांकों की सूची की सूची देता है में बदल जाते हैं की एक सूची ले लो। दुर्भाग्य से Scalaz तो यह कोड संकलन नहीं है Parser
के लिए एक Applicative
उदाहरण प्रदान नहीं करता है, लेकिन यह है कि ठीक करने के लिए आसान है:
import scala.util.parsing.combinator._
import scalaz._
import Scalaz._
object parser extends RegexParsers {
val parsers = List(1, 2, 3).map(repN(_, """\d+""".r))
def apply(s: String) = parseAll(parsers.sequence, s)
implicit def ParserPure: Pure[Parser] = new Pure[Parser] {
def pure[A](a: => A) = success(a)
}
implicit def ParserFunctor: Functor[Parser] = new Functor[Parser] {
def fmap[A, B](p: Parser[A], f: A => B) = p.map(f)
}
implicit def ParserBind: Bind[Parser] = new Bind[Parser] {
def bind[A, B](p: Parser[A], f: A => Parser[B]) = p.flatMap(f)
}
}
यह अपेक्षा के अनुरूप काम करता है: parser("1 2 3 4 5 6")
हमें List(List(1), List(2, 3), List(4, 5, 6))
देता है, उदाहरण के लिए।
(मैं जानता हूँ कि मैं सिर्फ एक Apply
उदाहरण दे सकता है, लेकिन Bind
उदाहरण अधिक संक्षिप्त है।)
यह इस हर बार जब हम विस्तार Parsers
क्या करना है के लिए नहीं अच्छा होगा, लेकिन मैं स्पष्ट नहीं कर रहा हूँ उदाहरण Parsers#Parser
के लिए आम तौर पर कैसे प्राप्त करें। निश्चित रूप से निम्नलिखित अनुभवहीन दृष्टिकोण काम नहीं करता है, क्योंकि हम Parsers
के उदाहरण की जरूरत है कर दें:
implicit def ParserBind: Bind[Parsers#Parser] = new Bind[Parsers#Parser] {
def bind[A, B](p: Parsers#Parser[A], f: A => Parsers#Parser[B]) = p.flatMap(f)
}
यह बहुत मेरे लिए स्पष्ट है कि यह संभव होना चाहिए है, लेकिन मैं स्काला के साथ काफी सहज महसूस नहीं कर रहा हूँ यह जानने के लिए सिस्टम टाइप करें कि इसके बारे में कैसे जाना है। क्या कुछ आसान है जो मुझे याद आ रही है?
नीचे जवाब के जवाब में: मैं -Ydependent-method-types
मार्ग की कोशिश किया था, और यह अब तक मिल गया:
implicit def ParserApplicative(g: Parsers): Applicative[g.Parser] = {
val f = new Functor[g.Parser] {
def fmap[A, B](parser: g.Parser[A], f: A => B) = parser.map(f)
}
val b = new Bind[g.Parser] {
def bind[A, B](p: g.Parser[A], f: A => g.Parser[B]) = p.flatMap(f)
}
val p = new Pure[g.Parser] {
def pure[A](a: => A) = g.success(a)
}
Applicative.applicative[g.Parser](p, FunctorBindApply[g.Parser](f, b))
}
समस्या (के रूप में didierd बताते हैं) है कि यह implicit
पाने के लिए स्पष्ट नहीं है कि है । में किक करने तो इस दृष्टिकोण काम करता है, लेकिन आप अपने व्याकरण के लिए निम्न की तरह कुछ जोड़ने के लिए:
implicit val applicative = ParserApplicative(this)
उस बिंदु मिश्रण पर दृष्टिकोण में स्पष्ट रूप से अधिक आकर्षक है।
(एक साइड नोट के रूप में: मुझे बस Applicative.applicative[g.Parser]
लिखने में सक्षम होने की उम्मीद है, लेकिन यह एक त्रुटि देता है कि संकलक Pure[g.Parser]
के लिए एक अंतर्निहित मूल्य नहीं ढूंढ सकता है - भले ही कोई इसके बगल में बैठा हो। तो स्पष्ट रूप से वहाँ कुछ निर्भर विधि प्रकार के लिए जिस तरह से implicits काम के बारे में अलग है।) पूरा करता है कि क्या मैं यहाँ चाहते हैं एक चाल ओर इशारा करते हुए के लिए retronym को
धन्यवाद। मैं his code से निम्नलिखित निकाला गया है:
implicit def parserMonad[G <: Parsers with Singleton] =
new Monad[({ type L[T] = G#Parser[T] })#L] {
def pure[A](a: => A): G#Parser[A] = {
object dummy extends Parsers
dummy.success(a).asInstanceOf[G#Parser[A]]
}
def bind[A, B](p: G#Parser[A], f: (A) => G#Parser[B]): G#Parser[B] =
p.flatMap(f)
}
आप दायरे में इस है, तो आप एक इकाई उदाहरण Parser
के लिए किसी भी Parsers
विस्तार वस्तु में मिलता है। यह कास्ट की वजह से धोखाधड़ी की तरह है, लेकिन अभी भी बहुत साफ है।
यह चालाक और मेरे निर्भर विधि प्रकार संस्करण की तुलना में बहुत अच्छे है, लेकिन मैं अभी भी है कि 'निहित वैल एम के बिना क्या करना चाहते हैं: इकाई [पार्सर] = parserMonad (testParser)' । क्या आपको लगता है कि यह संभव नहीं है? –
मुझे 'सफलता' कॉल करने के लिए 'पार्सर्स' का उदाहरण होना चाहिए। आप 'पार्सर' को इसे 'पार्सरमोनाड' फ़ीड करने के लिए खुद को निहित कर सकते हैं, लेकिन यह एक अच्छा विचार नहीं लगता है। – retronym
यदि आप 'asInstanceOf' को स्वीकार करने के इच्छुक हैं, तो आप वास्तव में यह कर सकते हैं: https://github.com/retronym/scalaz7-experimental/commit/aa80e4792799a509c728eecff771ec74518720e7 – retronym