Scala 中的“Prolog 风格”:与过程代码混合?

2024-04-14

继续Scala 中的“prolog 风格”是什么? https://stackoverflow.com/questions/73611934/what-is-prolog-style-in-scala

我想在 Scala-3 中结合逻辑推理和过程代码。像这样的事情:

// This is a mix of Prolog and Scala, and is not a real code.
// The idea is not only to find out that the goal is reachable,
// but to use the found solution

print_file(X:Filename) :- read(X,Representation), print(Representation).
read(X:Filename, CollectionOfLines[X]) :- { read_lines(X) }.
read(X:Filename, String[X]) :- { slurp_file(X) }.
print(X:String) :- { print(X) }.
print(X:CollectionOfLines) :- { X.foreach(println)}.

given Filename("foo.txt")
val howto = summon[print_file]
howto()

我希望这种程序能够打印指定的文件。但到目前为止我不知道如何在 Scala 中指定程序部分。


(这篇文章包含的代码旨在演示类型系统的一些属性;它没有直接的实际应用,请不要将其用于任何用途;“它可以完成”并不意味着“你应该这样做”)

在你的问题中,并不完全清楚诸如“CollectionOfLines[X]" and "String[X]” 的意思是。我冒昧地将它扭曲成可实现的东西:

/**
 * Claims that an `X` can be printed.
 */
trait Print[X]:
  def apply(x: X): Unit

/**
 * Claims that an instance of type `X` can
 * be read from a file with a statically
 * known `Name`.
 */
trait Read[Name <: String & Singleton, X]:
  def apply(): X

/**
 * Claims that an instance of type `Repr` can
 * be read from a statically known file with a given `Name`,
 * and then printed in `Repr`-specific way.
 */
trait PrintFile[Name, Repr]:
  def apply(): Unit

given splitLines: Conversion[String, List[String]] with
  def apply(s: String) = s.split("\n").toList

given printFile[Name <: String & Singleton, Repr]
  (using n: ValueOf[Name], rd: Read[Name, Repr], prnt: Print[Repr])
: PrintFile[Name, Repr] with
  def apply(): Unit =
    val content = rd()
    prnt(content)

given readThenConvert[Name <: String & Singleton, A, B]
  (using name: ValueOf[Name], readA: Read[Name, A], conv: Conversion[A, B])
: Read[Name, B] with
  def apply() = conv(readA())

inline given slurp[Name <: String & Singleton]
  (using n: ValueOf[Name])
: Read[Name, String] with
  def apply() = io.Source.fromFile(n.value).getLines.mkString("\n")

given printString: Print[String] with
  def apply(s: String) = println(s)

given printList[X](using printOne: Print[X]): Print[List[X]] with
  def apply(x: List[X]) = x.zipWithIndex.foreach((line, idx) => {
    print(s"${"%3d".format(idx)}| ")
    printOne(line)
  })

@main def printItself(): Unit =
  println("Print as monolithic string")
  summon[PrintFile["example.scala", String]]()
  println("=" * 80)
  println("Print as separate lines")
  summon[PrintFile["example.scala", List[String]]]()


当另存为example.scala,它将打印自己的代码两次,一次作为一个长多行字符串,一次作为编号行列表。

正如其他地方已经提到的,这个特定的用例看起来非常不典型,而且代码看起来很不惯用。

你应该尝试保留这个机制true and precise有关类型和类型构造函数的语句,而不是用于在一堆命令性语句之间强制执行顺序。

在这个例子中,我们没有仔细地做出普遍正确的陈述,而是做出了一堆半生不熟、未经深思熟虑的陈述,给它们半随机的名称,然后试图滥用名义类型系统并强制现实我们通过给事物这样或那样命名而施加的人为限制。这通常是糟糕设计的标志:一切都感觉松散且有点“松弛”。这apply(): Unit特别是明显是一个危险信号:没有什么可说的Unit它也可以被编码为类型,因此我们必须恢复到“字符串类型”命名规则,而不是依赖于类型系统,然后希望人们能够正确解释这些名称。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 中的“Prolog 风格”:与过程代码混合? 的相关文章

随机推荐