There is a Prolog
in your Scala!
@folone Scala eXchange ‘13
One particular
approach
8+ implicits
FnHipsterAux
Logic
Programming
programmation en
logique, 1972, 5GL
Lingua franca
A language that doesn't
affect the way you think
about programming,
is not worth knowing.
— Alan J. Perlis
Buran
IBM Watson
What > How
Relations > Functions
Facts
Rules (to generate more facts)
Main principles
It's all about formulating the question.
Expressed with
Predicates > Functions
Map inputs to outputs
Run
Return some output
Define constraints
Match
Only return yes or no*
*If "yes", they may add bindings to variables.
log(2, 16, 4). log(2, 16) = 4
— How many Prolog
programmers does it take
to change a lightbulb?
— How many Prolog
programmers does it take
to change a lightbulb?
NO.
Scala eXchange
tracks planning
https://github.com/folone/scalaeXchange/
Facts
talk_about(dpp, webdev).
talk_about(milessabin, typelevel).
talk_about(larsr_h, typelevel).
talk_about(xeno_by, macros).
talk_about(milessabin, macros).
talk_about(sirthias, webdev).
Questions
?- talk_about(milessabin, webdev).
no
?- talk_about(larsr_h, typelevel).
yes
?- talk_about(dpp, X).
X = webdev.
?- talk_about(milessabin, X).
X = typelevel ;
X = macros.
Questions
?- talk_about(Who, What).
Who = dpp, What = webdev ;
Who = milessabin, What = typelevel ;
Who = milessabin, What = macros ;
Who = larsr_h, What = typelevel ;
Who = xeno_by, What = macros ;
Who = sirthias, What = webdev.
Rules
same_topic(Person1, Person2) :-
    talk_about(Person1, Topic),
    talk_about(Person2, Topic),
    Person1 == Person2.
?- same_topic(milessabin, Who).
Who = larsr_h ;
Who = xeno_by.
Facts
works_in(dpp, industry).
works_in(milessabin, industry).
works_in(milessabin, academia).
works_in(larsr_h, academia).
works_in(xeno_by, academia).
works_in(sirthias, industry).
same_topic(Person1, Person2) :-
talk_about(Person1, Topic), 
talk_about(Person2, Topic),
Person1 == Person2.
same_topic(Person1, Person2) :-
works_in(Person1, Area), 
works_in(Person2, Area), 
Person1 == Person2.
Questions
?- same_topic(dpp, Who).
Who = sirthias ;
Who = milessabin ;
Who = sirthias.
Rules
exactly_same_topic(Person1, Person2) :-
  talk_about(Person1, Topic),
  talk_about(Person2, Topic),
  works_in(Person1, Area),
  works_in(Person2, Area),
  Person1 == Person2.
Questions
?- exactly_same_topic(dpp, Who).
Who = sirthias.
?- exactly_same_topic(milessabin, Who).
Who = larsr_h ;
Who = xeno_by.
topic(Topic, Res) :-
  findall(Person, talk_about(Person, Topic), L1),
  Res = (Topic, L1).
environment(Area, Res) :-
  findall(Person, works_in(Person, Area), L1),
  Res = (Area, L1).
?- topic(webdev, List).
List = (webdev, [dpp, sirthias]).
?- environment(academia, List).
List = (academia, [milessabin, larsr_h, xeno_by]).
topics(L) :-
  findall(Topic, talk_about(_, Topic), L1),
  list_to_set(L1, L).
tracks(L) :-
  topics(L1),
  member(Topic, L1),
  topic(Topic, L).
?- topics(L).
L = [webdev, typelevel, macros].
?- tracks(L).
L = (webdev, [dpp, sirthias]) ;
L = (typelevel, [milessabin, larsr_h]) ;
L = (macros, [xeno_by, milessabin]).
Functional is imperative without state.
Logic is functional without manual search*.
* DFS
Scala is a logic
programming language...
in type system!
Scala is a logic
programming language...
TYPELEVEL
programming in Scala is...
in type system!
programming language...
logic programming
TYPELEVEL
programming in Scala is...
in type system!
in Scala!
Prolog
gcd(X, X, X).
gcd(X, Y, Out) :-
  X < Y
  Z is Y - X
  gcd(X, Z, Out).
gcd(X, Y, Out) :-
  Y < X,
  gcd(Y, X, Out).
trait GCD[X <: Nat, Y <: Nat] { type Out <: Nat }
object GCD
  def gcd[N<:Nat](x:Nat,y:Nat)(implicit gcd:Aux[x.N,y.N,N],wn:Witness.Aux[N]):N =
wn.value
  type Aux[X <: Nat, Y <: Nat, Z <: Nat] = GCD[X, Y] { type Out = Z }
Scala
{
implicit def gcd0[X <: Nat]:
Aux[X, X, X] =
new GCD[X, X] { type Out = X }
  implicit def gcd1[X <: Nat, Y <: Nat, Z <: Nat,
Out0 <: Nat]
    (implicit ev0 : LT[X, Y],
ev1 : Diff.Aux[Y, X, Z],
ev2 : Aux[X, Z, Out0]):
Aux[X, Y, Out0] =
      new GCD[X, Y] { type Out = Out0 }
  implicit def gcd2[X <: Nat, Y <: Nat, Out0 <: Nat]
    (implicit ev0 : LT[Y, X],
ev1 : Aux[Y, X, Out0]):
Aux[X, Y, Out0] =
new GCD[X, Y] { type Out = Out0}
}
Facts — implicit vals.
Rules — implicit defs taking implicit
vals as parameters.
Implication is the other way around.
Gotchas:
• Scala does not perform the DFS. In case of
multiple implicits, it does not compile. Prioritizing
implicits via inheritance.
• Diverging implicit expansion -Xlog-implicits.
• Extremely hard to debug (pen and paper style).
• Peculiar exceptions (SO in compiler, Method too
large, etc.)
— So now I need to redefine all the
goodness from prolog stdlib?! Lists,
naturals, etc.
Shapeless: stdlib for logic programming
in scala.
DEMO
https://github.com/folone/scalaeXchange/
Functional in the small,
OO in the large,
logic in the type system!
http://mitpress.mit.edu/books/art-prolog
shapeless (and all the typelevel.scala libraries)
metascala https://www.assembla.com/spaces/metascala/wiki
Links
@milessabin
@xeno_by
@travisbrown
@larsr_h
@killnicole
Thanks
?-
(λx.folonexlambda-calcul.us)@

There's a Prolog in your Scala!