Skip to content

Commit 45244e1

Browse files
committed
feat: add list creation methods
1 parent 3efa2f8 commit 45244e1

File tree

7 files changed

+50
-18
lines changed

7 files changed

+50
-18
lines changed

src/main/scala/io/github/kelvindev15/prolog/core/PrologList.scala

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,36 @@ trait PrologList extends RecursiveStruct:
77
val size: Int
88

99
object PrologList:
10+
extension (listTerminator: (PrologList | Variable))
11+
def linearizedArguments: Seq[Term] = listTerminator match
12+
case l: PrologList => l.linearizedArguments
13+
case v: Variable => Seq(v)
14+
15+
given Conversion[(PrologList | Variable), Term] = _.asInstanceOf[Term]
16+
1017
trait Cons extends PrologList:
1118
val head: Term
12-
val tail: PrologList
13-
override def linearizedArguments: Iterable[Term] = Seq(head) ++ tail.linearizedArguments
19+
val tail: (PrologList | Variable)
20+
21+
override def linearizedArguments: Seq[Term] = Seq(head) ++ tail.linearizedArguments
1422
override val arity: Int = 2
1523
override val arguments: Seq[Term] = Seq(head, tail)
1624
override val size: Int = linearizedArguments.size
1725
override val functor: Constant.Atom = Functors.CONS
1826

27+
def apply(elements: Term*): PrologList = elements.size match
28+
case 0 => Nil
29+
case 1 => Cons(elements.head, Nil)
30+
case _ => Cons(elements.head, apply(elements.tail *))
31+
1932
object Cons:
20-
def apply(head: Term, tail: PrologList): PrologList = ConsImpl(head, tail)
21-
33+
def apply(head: Term, tail: (PrologList | Variable)): PrologList = ConsImpl(head, tail)
34+
2235
object Nil extends PrologList:
23-
override def linearizedArguments: Iterable[Term] = Seq()
36+
override def linearizedArguments: Seq[Term] = Seq()
2437
override val arity: Int = 0
2538
override val arguments: Seq[Term] = Seq()
2639
override val size: Int = 0
2740
override val functor: Constant.Atom = Functors.EMPTY_LIST
2841

29-
private case class ConsImpl(head: Term, tail: PrologList) extends Cons
30-
31-
def apply(elements: Term*): PrologList = elements.size match
32-
case 0 => Nil
33-
case 1 => Cons(elements.head, Nil)
34-
case _ => Cons(elements.head, apply(elements.tail*))
42+
private case class ConsImpl(head: Term, tail: (PrologList | Variable)) extends Cons

src/main/scala/io/github/kelvindev15/prolog/core/RecursiveStruct.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package io.github.kelvindev15.prolog.core
33
import io.github.kelvindev15.prolog.utils.BinaryToFlatVisitor
44

55
trait RecursiveStruct extends Struct:
6-
def linearizedArguments: Iterable[Term]
6+
def linearizedArguments: Seq[Term]
77

88
object RecursiveStruct:
99
trait BinaryRecursiveStruct extends RecursiveStruct:
@@ -13,7 +13,7 @@ object RecursiveStruct:
1313
def left: Term
1414
def right: Term
1515
final override val arguments: Seq[Term] = Seq(left, right)
16-
override def linearizedArguments: Iterable[Term] = accept(BinaryToFlatVisitor())
16+
override def linearizedArguments: Seq[Term] = accept(BinaryToFlatVisitor())
1717

1818
object BinaryRecursiveStruct:
1919
def wrapIfNecessary(struct: Seq[Term] => BinaryRecursiveStruct)(args: Term*): Term = args.size match

src/main/scala/io/github/kelvindev15/prolog/dsl/DSLFacilities.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import scala.annotation.targetName
99
object DSLFacilities:
1010
given Conversion[String, Atom] = Atom(_)
1111
given Conversion[AnyVal, Constant.Numeric] = Constant.Numeric(_)
12-
12+
1313
extension (atom: Atom)
1414
def apply(terms: Term*): Struct = Struct(atom, terms *)
1515

@@ -19,6 +19,7 @@ object DSLFacilities:
1919
@targetName("iff")
2020
def :-(body: Term): Rule = Rule(struct, body)
2121
def and(other: Term): Struct = Goals.Conjunction(struct, other)
22+
def or(other: Term): Struct = Goals.Disjunction(struct, other)
2223

2324
@targetName("iff")
2425
def :-(terms: Term*): Directive = Directive(terms*)

src/main/scala/io/github/kelvindev15/prolog/dsl/PrologDSL.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.github.kelvindev15.prolog.dsl
22

3+
import io.github.kelvindev15.prolog.core.PrologList.{Cons, Nil}
34
import io.github.kelvindev15.prolog.core.Struct.Clause
5+
import io.github.kelvindev15.prolog.core.{PrologList, Term, Variable}
46
import io.github.kelvindev15.prolog.core.Theory.Theory
57

68
import scala.annotation.targetName
@@ -10,5 +12,8 @@ trait PrologDSL:
1012
export DSLVariables.*
1113

1214
def theory(clauses: Clause*): Theory = Theory(clauses*)
13-
15+
def list(terms: Term*): PrologList = PrologList(terms *)
16+
def cons(term: Term, tail: (PrologList | Variable)): PrologList = Cons(term, tail)
17+
def nil: PrologList = Nil
18+
1419

src/main/scala/io/github/kelvindev15/prolog/utils/BinaryToFlatVisitor.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import io.github.kelvindev15.prolog.core.RecursiveStruct.BinaryRecursiveStruct
44
import io.github.kelvindev15.prolog.core.RecursiveStruct.BinaryRecursiveStruct.Tuple
55
import io.github.kelvindev15.prolog.core.Term
66

7-
class BinaryToFlatVisitor extends TermVisitor[Iterable[Term]]:
8-
override def visit(tuple: BinaryRecursiveStruct): Iterable[Term] = tuple match
7+
class BinaryToFlatVisitor extends TermVisitor[Seq[Term]]:
8+
override def visit(tuple: BinaryRecursiveStruct): Seq[Term] = tuple match
99
case Tuple(l, r @ Tuple(_, _)) => Seq(l) ++ visit(r)
1010
case Tuple(l, r) => Seq(l, r)

src/test/scala/io/github/kelvindev15/dsl/TestDSL.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,11 @@ class TestDSL extends AnyFunSuite with Matchers with PrologDSL {
5050
t should have size 2
5151
t.head shouldBe Fact(Struct(Atom("search"), Variable("X"), Struct(Atom("cons"), Variable("X"), anonymous())))
5252
}
53+
54+
test("Creation of lists") {
55+
cons("item1", nil).arguments shouldBe Seq(Atom("item1"), nil)
56+
cons(1, X).arguments should have size 2
57+
cons(H, T).variables shouldBe Seq(Variable("H"), Variable("T"))
58+
list(1, 2, 3) shouldBe cons(1, cons(2, cons(3, nil)))
59+
}
5360
}

src/test/scala/io/github/kelvindev15/prolog/core/TestRecursiveStructs.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package io.github.kelvindev15.prolog.core
33
import io.github.kelvindev15.prolog.core.Constant.Atom
44
import io.github.kelvindev15.prolog.core.Goals.{Conjunction, Disjunction}
55
import io.github.kelvindev15.prolog.core.PrologList.{Cons, Nil}
6-
import io.github.kelvindev15.prolog.core.{Constant, PrologList, Term, Variable}
76
import org.scalatest.funsuite.AnyFunSuite
87
import org.scalatest.matchers.should.Matchers
98

@@ -60,3 +59,15 @@ class TestRecursiveStructs extends AnyFunSuite with Matchers:
6059
test("Creation of a prolog list with Cons and Nil") {
6160
Cons(Atom("a"), Cons(Atom("b"), Cons(Atom("c"), Cons(Atom("d"), Nil)))) shouldBe list
6261
}
62+
63+
test("A list can end also with a variable") {
64+
val list = Cons(Atom("a"), Variable("X"))
65+
list shouldBe a [PrologList]
66+
list.linearizedArguments shouldBe Seq(Atom("a"), Variable("X"))
67+
}
68+
69+
test("A list not ending with a variable") {
70+
val list = PrologList(Atom("a"), Variable("X"))
71+
list shouldBe Cons(Atom("a"), Cons(Variable("X"), Nil))
72+
assert(list != Cons(Atom("a"), Variable("X")))
73+
}

0 commit comments

Comments
 (0)