2016-11-23 16 views
3

Итак, я пытаюсь инкапсулировать серию операций с gremlin-scala в HList так что я могу сделать RightFold над ними (это позволило бы мне построить запрос гремлина как данные: конкретно HList от Operations).Scala, гном-Скала, HLists, poly2, RightFold и недостающий неявное PREPEND

Вот что я имею в виду: как правило, вы можете сделать вызов gremlin-scala так:

import gremlin.scala._ 
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory 

def graph = TinkerFactory.createModern.asScala 
graph.V.hasLabel("person").out("created").as("creations").toList.map(_.valueMap) 

---> List[Map[String,Any]] = List(Map(name -> lop, lang -> java), Map(name -> ripple, lang -> java), Map(name -> lop, lang -> java), Map(name -> lop, lang -> java)) 

Это все хорошо, но я хочу, чтобы иметь возможность построить запрос в виде данных. Я моделирования это как HList из Operations как так:

sealed trait Operation 

case class VertexOperation[Labels <: HList](vertex: String) extends Operation { 
    def operate(graph: Graph): GremlinScala[Vertex, Labels] = { 
    graph.V.hasLabel(vertex).asInstanceOf[GremlinScala[Vertex, Labels]] 
    } 
} 

case class OutOperation[Labels <: HList](out: String) extends Operation { 
    def operate(vertex: GremlinScala[Vertex, Labels]): GremlinScala[Vertex, Labels] = { 
    vertex.out(out) 
    } 
} 

Тогда я смог бы создать запрос, поместив их в HList так:

import shapeless._ 

val query = OutOperation("created") :: VertexOperation("person") :: HNil 

Теперь, когда я их в HList, я могу сделать RightFold применять их по одному графику:

trait ApplyOperationDefault extends Poly2 { 
    implicit def default[T, L <: HList] = at[T, L] ((_, acc) => acc) 
} 

object ApplyOperation extends ApplyOperationDefault { 
    implicit def vertex[T, L <: HList, S <: HList] = at[VertexOperation[S], Graph] ((t, acc) => t.operate(acc)) 
    implicit def out[T, L <: HList, S <: HList] = at[OutOperation[S], GremlinScala[Vertex, S]] ((t, acc) => t.operate(acc)) 
} 

object Operation { 
    def process[Input, Output, A <: HList](operations: A, input: Input) (implicit folder: RightFolder.Aux[A, Input, ApplyOperation.type, Output]): Output = { 
    operations.foldRight(input) (ApplyOperation) 
    } 
} 

И называют это так:

val result = Operation.process(query, graph).toList 

Все это работает! И показывает большие надежды.

Вот где я получаю на мой вопрос: когда я пытаюсь сделать это с помощью as операции, я могу получить Operation компиляции:

case class AsOperation[A, In <: HList](step: String) extends Operation { 
    def operate(g: GremlinScala[A, In]) (implicit p: Prepend[In, ::[A, HNil]]): GremlinScala[A, p.Out] = { 
    g.as(step) 
    } 
} 

(я добавил, что (implicit p: Prepend[In, ::[A, HNil]]) там, потому что компилятор жалуясь иначе) ... но когда я пытаюсь создать неявную обработчик для этого случая, наряду с другими, он не:

implicit def as[T, L <: HList, A, In <: HList] = at[AsOperation[A, In], GremlinScala[A, In]] ((t, acc) => t.operate(acc)) 

---> could not find implicit value for parameter p: shapeless.ops.hlist.Prepend[In,shapeless.::[A,shapeless.HNil]] 

Итак, несколько вопросов здесь:

  • Что это такое неявное Prepend все о том, зачем оно мне нужно?
  • Почему он может найти неявный Prepend при вызове as нормально, но сбой при попытке RightFold над ним?
  • Как создать неявный экземпляр Prepend?
  • Как только я создал, как бы передать его вызову operate?
  • Что такое правильный способ?

У меня, наверное, больше вопросов, но это основные. Я читал в основном программирование на типе и бесформенное вообще, и я действительно люблю его, но этот вид сумасшествия. Я знаю, что есть какая-то тонкая вещь, которую я здесь отсутствует, но трудно понять, с чего начать дешифровать то, чего не хватает.

Спасибо за помощь! Я действительно хочу любить скала и бесформенность, надеясь скоро преодолеть это препятствие.

EDIT: Я сделал минимальное репо воспроизводя проблему здесь: https://github.com/bmeg/leprechaun

Хотелось бы надеяться, что помогает!

ответ

1

Ваше недоразумение - использование Prepend. Компилятор автоматически сгенерирует его для вас, вам не нужно будет создавать его вручную.

Как указано в Shapeless and gremlin scala: How do I return the result of a call to `as`?Prepend используется для хранения типов отмеченных этапов. Гремлин-скала readme.md углубляется.

компилятор на самом деле говорит вам именно то, что нужно: could not find implicit value for parameter p: shapeless.ops.hlist.Prepend[In,shapeless.::[A,shapeless.HNil]]

Так вот что я сделал: добавить неявную вставляться в рамки :) Я только что отправил вам PR, теперь отлично компилируется.

PS: Возможно, вы захотите обновить свои версии gremlin-scala.

+0

Интересно ... теперь любая функция, которую я называю этим методом 'as', мне также нужно объявить неявным' Prepend'. Любой способ избежать этого бесконечного регресса? В какой момент создается «Prepend»? – prismofeverything

+0

переместил обсуждение на https://gitter.im/mpollmeier/gremlin-scala –

 Смежные вопросы

  • Нет связанных вопросов^_^