To begin:
· In Eclipse create a Scala project called ListLab.
· Add a worksheet to this project called session
· Add a Scala interpreter to this project
In
the session worksheet define and test the following functions.
For each function implement four versions:
· Iterative version
· Recursive version
· Tail-recursive version (this should be different from the previous version)
· map-filter-reduce version
All of your implementations should be as
generic as possible.
To end:
· Export session.sc to your file system and send it to the grader by the deadline.
Write a function that computes the sum of cubes of all odd numbers occurring in a list of integers.
Write a function that computes the sum of numbers in a list of lists of numbers:
sumOfSums(List(List 1, 2, 3), List(4, 5, 6)) = 21
Write a function that returns the depth of a list of nested lists:
depth(List(List(List 1, 2, List(3)))) = 4
Write a function that computes the average of a list of doubles
Write a function that returns the largest element of a list of comparables.
Write a function that returns the number of elements in a list that satisfy a given predicate. (The predicate is a parameter of type T=>Boolean.)
Write a function that returns true if all elements in a list satisfy a given predicate.
Write a function that returns true if any element in a list satisfies a given predicate.
Write a function that reverses the elements in a list.
Write a function that returns true if a given list of comparables is sorted.
If the List.map function didn't exist, how would you define it?
If take, drop, and zip didn't exist for lists, how would you define them?
A stream is like a list except that it is constructed using the lazy version of cons:
scala> val s1 = 1 #:: 2
#:: 3 #:: Stream.Empty
s1: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> s1.head
res0: Int = 1
scala> s1.tail.head
res1: Int = 2
Create the following streams
· An infinitely long stream of 1's
· The stream of all non-negative integers
· The stream of all non-negative even integers
· The stream of all squares of integers
A logic program consists of a set of rules and facts:
Conclusion if Condition1 and Condition2 and ...
A fact is simply a conclusion without conditions.
For example:
Bart is the son of Homer if Bart is male and Homer is the parent of Bart
Bart is male
Homer is male
Homer is the parent of Lisa
Lisa is the daughter of Homer if Lisa is female and Homer is the parent of Lisa
Homer is the parent of Bart if Homer is the parent of Lisa and Lisa is the sister of Bart
Lisa is the sister of Bart if Lisa is female and Bart is the sibling of Lisa
Bart is the sibling of Lisa if Lisa is the sibling of Bart
Lisa is the sibling of Bart
etc.
Conclusions, goals, conditions, and facts are Boolean-valued predicates.
The three main logic programming languages are:
· Proplog- predicates are strings
· Datalog- predicates may also contain variables: X is the sibling of Y if Y is the sibling of X
· Prolog- predicates may also contain structures: Person(Name1, Age1) is the sibling of Person(Name2, Age2) if (Person(Name2, Age2) is the sibling of Person(Name1, Age1)
We can represent a logic program as a list of lists of statements:
val simpsons: List[List[String]] = List(
List("Bart is the son of Homer", "Bart is male", "Homer is the parent of
Bart")
List("Bart is male")
etc.
)
Given a list of goal statements and a logic program as input, a solver attempts to prove that each goal statement can be proved from the program:
def solve(goals: List[Statement], program: List[List[Statement]]): Boolean = if (program proves goals) true else false
In some cases solve may not terminate.
The main inference rule used is resolution:
Assume we have proved A1 and A2, then from the rule A if A1 and A2, we can infer A
In Prolog and Datalog solve also needs to find bindings for variables that will make a conclusion match with a goal, this is called unification:
Bart is the Sibling of Lisa
X is the sibling of Y if Y is the sibling of X
Lisa is the Sibling of Bart (assuming unifier = {X = Lisa, Y =
Bart})
Implement and test solve for Proplog.
Hints:
· Add a new Scala application object called proplog to a Scala project called proplog.
package proplog
object proplog extends App {
}
· Add an integer parameter, pos, to solve. Pos - 1 indicates the position in the program of the last rule or fact that matched the current goal:
package proplog
object proplog extends App {
def solve(goals: List[String], program:
List[List[String]], pos: Int = 0): Boolean = {...}
}
· If the goal list is empty, then return true, solve has satisfied all of the goals.
· If program length <= pos, return false, we're out of rules and facts to resolve with our goals.
· Assume A is the head of goals. Let (A, A1, A2, A3) be the first rule (or fact) in the program with index >= pos. (Use program.indexWhere(unifier _, pos).)
· If none exists, then return false, otherwise recursively call solve. The new list of goals is the old list with A replaced by A1, A2, A3. You can experiment with placing these conditions at the front or rear of goals. If A matches a fact, then A is simply removed from the goal list. It has been satisfied. Set pos = 0, we're starting over.
· If the above recursive call returns false, recursively call solve again. No changes to goals or program this time, but pos = index + 1. In other words, we look for the next fact or rule that might match A.
· Print out the goals and pos at the start of solve. This is the (attempted) proof.
· Add some test code to the app object and run it:
package proplog
object proplog extends App {
def solve(goals: List[String], program:
List[List[String]], pos: Int = 0): Boolean = {...}
var program1 = List(...)
var goals1 = List(...)
println("result = " +
solve(goals1, program1))
// etc.
}
Find an iterative implementation of solve
Find a non-recursive, non-iterative implementation of solve that uses map. filter, and reduce.