- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的应用程序中,我有一堆能够呈现 Html 的组件:
class StandardComponent {
def render: Html
}
它们在运行时由 ComponentBuilder
从 ComponentDefinition
对象实例化,它提供对运行时数据的访问:
class ComponentBuilder {
def makeComponent(componentDef: ComponentDefinition): StandardComponent
}
然后有几个助手可以促进组件内子组件的渲染:
def fromComponent(componentDef: ComponentDefinition)(htmlFn: Html => Future[Html])(implicit componentBuilder: ComponentBuilder): Future[Html]
def fromComponents(componentDefs: Seq[ComponentDefinition])(htmlFn: Seq[Html] => Future[Html])(implicit componentBuilder: ComponentBuilder): Future[Html]
def fromOptionalComponent(componentDefOpt: Option[ComponentDefinition])(htmlFn: Option[Html] => Future[Html])(implicit componentBuilder: ComponentBuilder): Future[Html]
def fromComponentMap[K](componentDefMap: Map[K, ComponentDefinition])(htmlFn: Map[K, Html] => Future[Html])(implicit componentBuilder: ComponentBuilder): Future[Html]
问题是,一个组件通常需要使用多个这样的 from*
调用。虽然它们被设计成可嵌套的,但它可能会变得有点乱:
implicit val componentBuilder: ComponentBuilder = ???
val subComponent: ComponentDefinition = ???
val subComponents: Seq[ComponentDefinition] = ???
val subComponentOpt: Option[ComponentDefinition] = ???
fromComponent(subComponent) { html =>
fromComoponents(subComponents) { htmls =>
fromOptionalComponent(subComponentOpt) { optHtml =>
???
}
}
}
我想做的大致是这样的:
withSubComponents(
subComponent, subComponents, subComponentOpt
) { case (html, htmls, optHtml) => /* as Html, Seq[Html], and Option[Html] */
???
}
因此,我想让 withSubComponents
在其参数中可变,并且我想让它在第二个参数列表中采用的闭包具有一个参数列表,该参数列表取决于 arity 中的第一个参数列表和类型。理想情况下,它还采用隐式 ComponentBuilder
,就像各个助手所做的那样。这是理想的语法,但我愿意接受其他选择。我可以提供一些我目前所拥有的例子,但到目前为止我所拥有的只是想法。感觉我需要制作 CoProduct 的 HList,然后我需要将两个参数联系在一起的方法。
最佳答案
改进 DSL 的第一步可以是将方法移动到像这样的隐式转换:
implicit class SubComponentEnhancements[T](subComponent: T)(
implicit cb: ComponentBuilder[T]) {
def fromComponent(f: cb.HtmlType => Future[Html]): Future[Html] = ???
}
请注意,我声明了 fromComponent
对每个定义了 ComponentBuilder
的类型 T
都有效。如您所见,我还设想了 ComponentBuilder
有一个 HtmlType
。在您的示例中,它是 Seq[Html]
、Option[Html]
等。ComponentBuilder
现在看起来像这样:
trait ComponentBuilder[T] {
type HtmlType
def render(componentDef: T): HtmlType
}
我还设想 ComponentBuilder
能够将组件呈现为某种类型的 Html
。让我们声明一些组件构建器,以便能够在不同类型上调用 fromComponent
方法。
object ComponentBuilder {
implicit def single =
new ComponentBuilder[ComponentDefinition] {
type HtmlType = Html
def render(componentDef: ComponentDefinition) = {
// Create standard component from a component definition
val standardComponent = new StandardComponent
standardComponent.render
}
}
implicit def seq[T](
implicit cb: ComponentBuilder[T]) =
new ComponentBuilder[Seq[T]] {
type HtmlType = Seq[cb.HtmlType]
def render(componentDef: Seq[T]) =
componentDef.map(c => cb.render(c))
}
implicit def option[T](
implicit cb: ComponentBuilder[T]) =
new ComponentBuilder[Option[T]] {
type HtmlType = Option[cb.HtmlType]
def render(componentDef: Option[T]) =
componentDef.map(c => cb.render(c))
}
}
请注意,每个组件构建器都指定了一个与 ComponentBuilder
的类型同步的 HtmlType
。容器类型的构建器只需为它们的内容请求一个组件构建器。这使我们无需过多的额外努力即可嵌套不同的组合。我们可以进一步推广这个概念,但现在这没问题。
至于单一
组件构建器,您可以定义得更通用,允许您拥有不同类型的组件定义。可以使用位于多个不同位置的 Converter
将它们转换为标准组件(X
的伴随对象,Converter
的伴随对象> 或用户需要手动导入的单独对象)。
trait Converter[X] {
def convert(c:X):StandardComponent
}
object ComponentDefinition {
implicit val defaultConverter =
new Converter[ComponentDefinition] {
def convert(c: ComponentDefinition):StandardComponent = ???
}
}
implicit def single[X](implicit converter: Converter[X]) =
new ComponentBuilder[X] {
type HtmlType = Html
def render(componentDef: X) =
converter.convert(componentDef).render
}
无论如何,代码现在如下所示:
subComponent fromComponent { html =>
subComponents fromComponent { htmls =>
subComponentOpt fromComponent { optHtml =>
???
}
}
}
这看起来是一个熟悉的模式,让我们重命名这些方法:
subComponent flatMap { html =>
subComponents flatMap { htmls =>
subComponentOpt map { optHtml =>
???
}
}
}
注意,我们是在一厢情愿的空间,上面的代码是不会编译通过的。如果我们有办法让它编译,我们可以编写如下内容:
for {
html <- subComponent
htmls <- subComponents
optHtml <- subComponentOpt
} yield ???
这对我来说看起来很神奇,不幸的是 Option
和 Seq
本身有一个 flatMap
函数,所以我们需要隐藏它们。下面的代码看起来很干净,让我们有机会隐藏 flatMap
和 map
方法。
trait Wrapper[+A] {
def map[B](f:A => B):Wrapper[B]
def flatMap[B](f:A => Wrapper[B]):Wrapper[B]
}
implicit class HtmlEnhancement[T](subComponent:T) {
def html:Wrapper[T] = ???
}
for {
html <- subComponent.html
htmls <- subComponents.html
optHtml <- subComponentOpt.html
} yield ???
如您所见,我们仍处于一厢情愿的空间,让我们看看是否可以填补空白。
case class Wrapper[+A](value: A) {
def map[B](f: A => B) = Wrapper(f(value))
def flatMap[B](f: A => Wrapper[B]) = f(value)
}
implicit class HtmlEnhancement[T](subComponent: T)(
implicit val cb: ComponentBuilder[T]) {
def html: Wrapper[cb.HtmlType] = Wrapper(cb.render(subComponent))
}
实现并不那么复杂,因为我们可以使用之前创建的工具。请注意,在一厢情愿的想法中,我返回了一个 Wrapper[T]
,而我们实际上需要 html,所以我现在使用组件构建器中的 HtmlType
。
为了改进类型推断,我们将稍微更改 ComponentBuilder
。我们会将 HtmlType
类型成员更改为类型参数。
trait ComponentBuilder[T, R] {
def render(componentDef: T): R
}
implicit class HtmlEnhancement[T, R](subComponent: T)(
implicit val cb: ComponentBuilder[T, R]) {
def html:Wrapper[R] = Wrapper(cb.render(subComponent))
}
不同的 build 者也需要改变
object ComponentBuilder {
implicit def single[X](implicit converter: Converter[X]) =
new ComponentBuilder[X, Html] {
def render(componentDef: X) =
converter.convert(componentDef).render
}
implicit def seq[T, R](
implicit cb: ComponentBuilder[T, R]) =
new ComponentBuilder[Seq[T], Seq[R]] {
def render(componentDef: Seq[T]) =
componentDef.map(c => cb.render(c))
}
implicit def option[T, R](
implicit cb: ComponentBuilder[T, R]) =
new ComponentBuilder[Option[T], Option[R]] {
def render(componentDef: Option[T]) =
componentDef.map(c => cb.render(c))
}
}
现在的最终结果是这样的:
val wrappedHtml =
for {
html <- subComponent.html
htmls <- subComponents.html
optHtml <- subComponentOpt.html
} yield {
// Do some interesting stuff with the html
htmls ++ optHtml.toSeq :+ html
}
// type of `result` is `Seq[Html]`
val result = wrappedHtml.value
// or
val Wrapper(result) = wrappedHtml
您可能已经注意到,我跳过了 Future
,您可以根据需要自行添加。
我不确定这是否是您设想的 DSL 的方式,但它至少为您提供了一些工具来创建一个非常酷的 DSL。
关于scala - 无形案例研究,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26318713/
我即将在 uni 开始关于 OpenCL 的荣誉项目,以及如何使用它来改进现代游戏开发。我知道现在/很快有几本书关于学习 opencl,但我想知道是否有人知道关于 opencl 的任何好论文。 我一直
在 Web 开发领域,我听过很多博客,人们说用户倾向于忽略(或被激怒)华而不实/不必要的动画内容,对可用性产生不利影响,但是否有任何研究支持那个声明? 最佳答案 我找到了一对似乎符合您正在寻找的路线。
我对网络语音和音频不熟悉。 我一直在谷歌上搜索示例和解决方案来实现 p2p 语音连接(这个想法是音频 session )。 我发现 google talk xmpp 框架可以访问用户和文本聊天等信息。
我打算创建一个优化的数据结构来保存汇编代码。这样我就可以完全负责将在这个结构上工作的优化算法。如果我可以边运行边编译。这将是一种动态执行。这可能吗?有没有人见过这样的事情? 我应该使用结构将结构链接到
低代码开发平台 Mendix 最新发布的一份研究报告表明,疫情在全球范围内的扩散大大加速了对企业低代码的兴趣和使用。该报告基于来自美国、中国、英国、德国、比利时和荷兰的 1209 名 IT 专业人士
最常用的数值类型是int,但是它未必是最佳选择。bigint,smallint,tinyint可以应用在特殊场合。他们的特性如下表所示: Data type
我试图了解在使用 R 包 kernlab 中的命令 ksvm 时 SVM 预测函数是如何工作的。 我尝试使用以下命令查看预测函数: methods(class="ksvm") getAnywhere(
据我了解,XMPP 协议(protocol)基于始终在线的连接,您无法立即指示 XML 消息何时结束。 这意味着您必须在流来时对其进行评估。这也意味着,您可能必须处理异步连接,因为套接字可能会阻塞在
两天后,我发现自己正在考虑通过网站上的 ajax 请求实现流程自动化。我想做的是研究网站上执行的某些操作的一些请求,并用 javascript 复制它。例如,当我在剧院选择一些座位时,我有这个 POS
当我研究我没有编写的复杂 Java 代码时,我会定期在记事本中写下一些我对给定问题感兴趣的资源的调用堆栈。这些资源通常是方法或常量。 这是一个例子: CONSTANT_NAME com.com
我将为 Android 智能手机实现一个蜜 jar 作为我论文的研究。我从来没有使用过android、java和蜜 jar 。这就是我想开始的方式。我想到使用Honeyd的源代码(用C语言编写),Ho
Closed. This question does not meet Stack Overflow guidelines 。它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 Stack Ov
晚上好。 我真的很难理解这个问题,我不确定我是否错过了一些非常愚蠢的东西,但这是我的代码和我的问题。 const question = new Map(); question.set('questio
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
我想知道是否有人有任何关于编译/链接优化的好资源(论文/文章/书籍引用)。 我曾在两家以不同方式执行链接操作的公司工作。 第一公司强制代码采用严格的 DAG 结构,向我解释说使用强制树结构,链接时间非
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
我有 4 个文件想用 Python/Pandas 读取,这些文件是: https://github.com/kelsey9649/CS8370Group/tree/master/TaFengDataS
我正在尝试查找任何分析 Qt 和 Qt Creator 最新版本的研究/学术/期刊论文/文章。 具体来说,我试图从实时安全关键的角度评估 Qt,所以任何信息都是有帮助的。 附言我尝试了典型的搜索方法:
在 Main Wrapper 中,我有 5 个 Div。第一个 div 包含 4 个 Box(box_1, box_2,box_3,box_4),我的点击事件将在其中发生。 另外4个div在main
所以,我一直在用 Netbeans C++ 调试一个程序,我需要仔细查看 vector 的内容,以帮助我找出哪里出了问题。因此,我进入“变量”选项卡进行挖掘。问题是,Netbeans(或我使用过的任何
我是一名优秀的程序员,十分优秀!