PDA for Context Free Grammar - grammar

G = ({S, X, Y}, {a, b}, P, S)
P = {
S -> aXY | XbY
X -> bX | aS | e
Y -> a | e
}
What is the language generated by this grammar? and which automaton accepts by empty stack, this language?

Related

Typed Lambda Calculus

I want to find the type of the lambda expression \x y -> x y y. I proceed as follows.
We go in the reverse order of operations and "unpack" the expression. Assume the whole expression has type A. Then let y have type x1 and \x y -> x y have type B. Then A = B -> x1
We already know the type of y, and let \x y -> x be of the type C. Then B = C -> x1.
The type of \x y -> x is obviously x1->x2->x1. This is given to us in the previous exercise and makes sense because this expression takes in two arguments and returns the first.
Putting it all together we have that:
A = B -> x1 = C -> x1 -> x1 = (x1 -> x2 -> x1) -> x1 -> x1
The correct answer is somehow:
(x1 -> x1 -> x2) -> x1 -> x2
What am I doing wrong?
Here I just write stuff's types under it and go from there:
foo = \x y -> x y y
foo x y = x y y
a b : c
a b b : c
a b : b -> c
a : b -> b -> c
foo : a -> b -> c
~ (b -> b -> c) -> b -> c
And another one:
bar = \x y -> x (y x)
bar x y = x (y x)
a b : c
a (b a) : c
---------
b a : d
b : a -> d
a : d -> c
bar : a -> b -> c
~ (d -> c) -> ( a -> d) -> c
~ (d -> c) -> ((d -> c) -> d) -> c
But,
baz x = x x
a a a : b
a : a -> b
baz : a -> b
~ (a -> b) -> b
~ ((a -> b) -> b) -> b
~ (((a -> b) -> b) -> b) -> b
........
is an "infinite" type, i.e. the process of type derivation never stops.

Polynomial evaluation in Isabelle

In the book Concrete Semantics, exercise 2.11 writes:
Define arithmetic expressions in one variable over integers
(type int) as a data type:
datatype exp = Var | Const int | Add exp exp | Mult exp exp
Define a function eval :: exp ⇒ int ⇒ int such that eval e x evaluates e at the value x. A polynomial can be represented as a list of coefficients, starting with the constant. For example, [4, 2, − 1, 3] represents the polynomial 4+2x−x 2 +3x 3 . Define a function evalp :: int list ⇒ int ⇒ int that evaluates a polynomial at the given value. Define a function coeffs :: exp ⇒ int list that transforms an
expression into a polynomial. This may require auxiliary functions. Prove that coeffs preserves the value of the expression: evalp (coeffs e) x = eval e x. Hint: consider the hint in Exercise 2.10.
As a first try, and because former exercises encouraged to write iterative versions of functions, I wrote the following:
datatype exp = Var | Const int | Add exp exp | Mult exp exp
fun eval :: "exp ⇒ int ⇒ int" where
"eval Var x = x"
| "eval (Const n) _ = n"
| "eval (Add e1 e2) x = (eval e1 x) + (eval e2 x)"
| "eval (Mult e1 e2) x = (eval e1 x) * (eval e2 x)"
fun evalp_it :: "int list ⇒ int ⇒ int ⇒ int ⇒ int" where
"evalp_it [] x xpwr acc = acc"
| "evalp_it (c # cs) x xpwr acc = evalp_it cs x (xpwr*x) (acc + c*xpwr)"
fun evalp :: "int list ⇒ int ⇒ int" where
"evalp coeffs x = evalp_it coeffs x 1 0"
fun add_coeffs :: "int list ⇒ int list ⇒ int list" where
"add_coeffs [] [] = []"
| "add_coeffs (a # as) (b# bs) = (a+b) # (add_coeffs as bs)"
| "add_coeffs as [] = as"
| "add_coeffs [] bs = bs"
(there might be some zip function to do this)
fun mult_coeffs_it :: "int list ⇒ int list ⇒ int list ⇒ int list ⇒ int list" where
"mult_coeffs_it [] bs accs zeros = accs"
| "mult_coeffs_it (a#as) bs accs zeros =
mult_coeffs_it as bs (add_coeffs accs zeros#bs) (0#zeros)"
fun mult_coeffs :: "int list ⇒ int list ⇒ int list" where
"mult_coeffs as bs = mult_coeffs_it as bs [] []"
fun coeffs :: "exp ⇒ int list" where
"coeffs (Var) = [0,1]"
| "coeffs (Const n) = [n]"
| "coeffs (Add e1 e2) = add_coeffs (coeffs e1) (coeffs e2)"
| "coeffs (Mult e1 e2) = mult_coeffs (coeffs e1) (coeffs e2)"
I tried to verify the sought theorem
lemma evalp_coeffs_eval: "evalp (coeffs e) x = eval e x"
but could not. Once I got an advice that writing good definitions is very important in theorem proving, though the adviser did not give details.
So, what is the problem with my definitions, conceptually? Please do not write the good definitions but point out the conceptual problems with my definitions.
UPDATE: upon advice I started to use
fun evalp2 :: "int list ⇒ int ⇒ int" where
"evalp2 [] v = 0"|
"evalp2 (p#ps) v = p + v * (evalp2 ps v) "
and looking into src/HOL/Algebra/Polynomials.thy I formulated
fun add_cffs :: "int list ⇒ int list ⇒ int list" where
"add_cffs as bs =
( if length as ≥ length bs
then map2 (+) as (replicate (length as - length bs) 0) # bs
else add_cffs bs as)"
but that did not help much, simp add: algebra_simps or arith did not solve the corresponding subgoal.
Some hints:
Try running quickcheck and nitpick on the Lemma until no more counter example is found. For the Lemma in your question I get the following counter example:
Quickcheck found a counterexample:
e = Mult Var Var
x = - 2
Evaluated terms:
evalp (coeffs e) x = - 10
eval e x = 4
Try to prove some useful Lemmas about your auxiliary functions first. For example:
lemma "evalp (mult_coeffs A B) x = evalp A x * evalp B x"
Read about calculating with polynomials (e.g. https://en.wikipedia.org/wiki/Polynomial_ring) and choose definitions close to what mathematicians do. Although this one might spoil the fun of coming up with a definition on your own.

is == distributive over logical OR in any programming language ? ( can we write (a==b || a==c) as a==(b||c))

Is there a provision in any programming language such that we can write (a==b || a==c) as a==(b||c)?
In other words, is == distributive over logical OR in any programming language? (can we write (a==b || a==c) as a==(b||c)).
There are similar constructs in several languages. IN in SQL, in in python, etc, most evaluating lists or arrays. Closest one I know is Haskell's or which has the type [Bool] -> Bool.
As Anton Gogolev said, it's hard to find a good type for b || c, but not entirely impossible.
You may have to define the higher order function (|||) :: forall a . a -> a -> ((a -> Bool) -> Bool) implemented as a (|||) b = \f -> (f x) || (f y) (here \ means the lambda expression).
Now you can use this (b ||| c) (== 42).
Alternatively you could do :
(|||) :: forall a b . a -> a -> (a -> b -> Bool) -> b -> Bool
(|||) x y f b = (f x b) || (f y b)
and now you can do ( a ||| b ) (==) 42
Of course none of the above will work in languages lacking higher order functions. Moreover, Equality (==) must be function and not language construct. (You can get similar effect with Promises, however).
Maybe the above lines give hints why this approach is not commonly used in the wild. :) a in [b,c] is much simpler to use.
EDIT: (for fun sake)
You can use wrapper type to achieve the goal (in Haskell):
data F a = (Eq a) => Fn (a -> (a->a->Bool) -> Bool) | N a
(===) :: Eq a => F a -> F a -> Bool
(Fn f) === (N n) = f n (==)
(N n) === (Fn f) = f n (==)
(N a) === (N b) = a == b
(Fn a) === (Fn b) = error "not implemented"
(|||) :: Eq a => F a -> F a -> F a
N a ||| N b = Fn $ \c f -> (a `f` c) || (b `f` c)
Fn a ||| N b = Fn $ \c f -> a c f || ( b `f` c )
N a ||| Fn b = Fn $ \c f -> b c f || ( a `f` c )
Fn a ||| Fn b = Fn $ \c f -> (a c f) || (b c f)
Now our new (===) is distributive over (|||). Some efforts has been made to keep associative and commutative properties. Now we can have all of the following:
N 1 === N 2
N 3 === ( N 3 ||| N 8 ||| N 5 )
( N 3 ||| N 8 ||| N 5 ) === N 0
N "bob" === ( N "pete" ||| N "cecil" ||| N "max")
N a === ( N 9 ||| N b ||| N c)
Everything will work smoothly. We could replace standard operators and type N with basic types and write 3 == (3 || 8 || 5). What you ask for is not impossible.
The construct is generic, you can easily extend it with something like (>=) :: F a -> F a -> Bool and now you can use ( 100 || 3 || a || b ) >= c. (Please notice that no lists or arrays are used.)

F# namespaces and modules : Awesome collections from Wikibooks

I'm trying to use the library AwesomeCollections on Wikibooks
https://en.wikibooks.org/wiki/F_Sharp_Programming/Advanced_Data_Structures
From that page, i have copied paste in 2 separate files code marked for .fsi and .fs
I must admit i don't understand well how .fsi and .fs files interact, and that explanations such those found on https://msdn.microsoft.com/en-us/library/dd233196.aspx are cryptic to me.
with a bit of re-formating, if i make a solution and use only the .fs file, it works fine.
However, using both the .fsi and .fs file, i get Error message such as
"the namespace 'Heap' is not defined" (in the main .fs file of the project)
"No constructors are available for the type 'int BinaryHeap'" (in the main .fs file of the project)
"Unexpected keyword 'type' in implementation file" (when trying to define the type Queue in the .fs file)
(* AwesomeCollections.fsi *)
namespace AwesomeCollections
type 'a stack =
| EmptyStack
| StackNode of 'a * 'a stack
module Stack = begin
val hd : 'a stack -> 'a
val tl : 'a stack -> 'a stack
val cons : 'a -> 'a stack -> 'a stack
val empty : 'a stack
val rev : 'a stack -> 'a stack
end
[<Class>]
type 'a Queue =
member hd : 'a
member tl : 'a Queue
member enqueue : 'a -> 'a Queue
static member empty : 'a Queue
[<Class>]
type BinaryTree<'a when 'a : comparison> =
member hd : 'a
member left : 'a BinaryTree
member right : 'a BinaryTree
member exists : 'a -> bool
member insert : 'a -> 'a BinaryTree
member print : unit -> unit
static member empty : 'a BinaryTree
//[<Class>]
//type 'a AvlTree =
// member Height : int
// member Left : 'a AvlTree
// member Right : 'a AvlTree
// member Value : 'a
// member Insert : 'a -> 'a AvlTree
// member Contains : 'a -> bool
//
//module AvlTree =
// [<GeneralizableValue>]
// val empty<'a> : AvlTree<'a>
[<Class>]
type 'a BinaryHeap =
member hd : 'a
member tl : 'a BinaryHeap
member insert : 'a -> 'a BinaryHeap
member merge : 'a BinaryHeap -> 'a BinaryHeap
interface System.Collections.IEnumerable
interface System.Collections.Generic.IEnumerable<'a>
static member make : ('b -> 'b -> int) -> 'b BinaryHeap
AwesomeCollections.fs
(* AwesomeCollections.fs *)
namespace AwesomeCollections
type 'a stack =
| EmptyStack
| StackNode of 'a * 'a stack
module Stack =
let hd = function
| EmptyStack -> failwith "Empty stack"
| StackNode(hd, tl) -> hd
let tl = function
| EmptyStack -> failwith "Emtpy stack"
| StackNode(hd, tl) -> tl
let cons hd tl = StackNode(hd, tl)
let empty = EmptyStack
let rec rev s =
let rec loop acc = function
| EmptyStack -> acc
| StackNode(hd, tl) -> loop (StackNode(hd, acc)) tl
loop EmptyStack s
type Queue<'a>(f : stack<'a>, r : stack<'a>) =
let check = function
| EmptyStack, r -> Queue(Stack.rev r, EmptyStack)
| f, r -> Queue(f, r)
member this.hd =
match f with
| EmptyStack -> failwith "empty"
| StackNode(hd, tl) -> hd
member this.tl =
match f, r with
| EmptyStack, _ -> failwith "empty"
| StackNode(x, f), r -> check(f, r)
member this.enqueue(x) = check(f, StackNode(x, r))
static member empty = Queue<'a>(Stack.empty, Stack.empty)
type color = R | B
type 'a tree =
| E
| T of color * 'a tree * 'a * 'a tree
module Tree =
let hd = function
| E -> failwith "empty"
| T(c, l, x, r) -> x
let left = function
| E -> failwith "empty"
| T(c, l, x, r) -> l
let right = function
| E -> failwith "empty"
| T(c, l, x, r) -> r
let rec exists item = function
| E -> false
| T(c, l, x, r) ->
if item = x then true
elif item < x then exists item l
else exists item r
let balance = function (* Red nodes in relation to black root *)
| B, T(R, T(R, a, x, b), y, c), z, d (* Left, left *)
| B, T(R, a, x, T(R, b, y, c)), z, d (* Left, right *)
| B, a, x, T(R, T(R, b, y, c), z, d) (* Right, left *)
| B, a, x, T(R, b, y, T(R, c, z, d)) (* Right, right *)
-> T(R, T(B, a, x, b), y, T(B, c, z, d))
| c, l, x, r -> T(c, l, x, r)
let insert item tree =
let rec ins = function
| E -> T(R, E, item, E)
| T(c, a, y, b) as node ->
if item = y then node
elif item < y then balance(c, ins a, y, b)
else balance(c, a, y, ins b)
(* Forcing root node to be black *)
match ins tree with
| E -> failwith "Should never return empty from an insert"
| T(_, l, x, r) -> T(B, l, x, r)
let rec print (spaces : int) = function
| E -> ()
| T(c, l, x, r) ->
print (spaces + 4) r
printfn "%s %A%A" (new System.String(' ', spaces)) c x
print (spaces + 4) l
type BinaryTree<'a when 'a : comparison> (inner : 'a tree) =
member this.hd = Tree.hd inner
member this.left = BinaryTree(Tree.left inner)
member this.right = BinaryTree(Tree.right inner)
member this.exists item = Tree.exists item inner
member this.insert item = BinaryTree(Tree.insert item inner)
member this.print() = Tree.print 0 inner
static member empty = BinaryTree<'a>(E)
type 'a heap =
| EmptyHeap
| HeapNode of int * 'a * 'a heap * 'a heap
module Heap =
let height = function
| EmptyHeap -> 0
| HeapNode(h, _, _, _) -> h
(* Helper function to restore the leftist property *)
let makeT (x, a, b) =
if height a >= height b then HeapNode(height b + 1, x, a, b)
else HeapNode(height a + 1, x, b, a)
let rec merge comparer = function
| x, EmptyHeap -> x
| EmptyHeap, x -> x
| (HeapNode(_, x, l1, r1) as h1), (HeapNode(_, y, l2, r2) as h2) ->
if comparer x y <= 0 then makeT(x, l1, merge comparer (r1, h2))
else makeT (y, l2, merge comparer (h1, r2))
let hd = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> x
let tl comparer = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> merge comparer (l, r)
let rec to_seq comparer = function
| EmptyHeap -> Seq.empty
| HeapNode(h, x, l, r) as node -> seq { yield x; yield! to_seq comparer (tl comparer node) }
type 'a BinaryHeap(comparer : 'a -> 'a -> int, inner : 'a heap) =
(* private *)
member this.inner = inner
(* public *)
member this.hd = Heap.hd inner
member this.tl = BinaryHeap(comparer, Heap.tl comparer inner)
member this.merge (other : BinaryHeap<_>) = BinaryHeap(comparer, Heap.merge comparer (inner, other.inner))
member this.insert x = BinaryHeap(comparer, Heap.merge comparer (inner,(HeapNode(1, x, EmptyHeap, EmptyHeap))))
interface System.Collections.Generic.IEnumerable<'a> with
member this.GetEnumerator() = (Heap.to_seq comparer inner).GetEnumerator()
interface System.Collections.IEnumerable with
member this.GetEnumerator() = (Heap.to_seq comparer inner :> System.Collections.IEnumerable).GetEnumerator()
static member make(comparer) = BinaryHeap<_>(comparer, EmptyHeap)
type 'a lazyStack =
| Node of Lazy<'a * 'a lazyStack>
| EmptyStack
module LazyStack =
let (|Cons|Nil|) = function
| Node(item) ->
let hd, tl = item.Force()
Cons(hd, tl)
| EmptyStack -> Nil
let hd = function
| Cons(hd, tl) -> hd
| Nil -> failwith "empty"
let tl = function
| Cons(hd, tl) -> tl
| Nil -> failwith "empty"
let cons(hd, tl) = Node(lazy(hd, tl))
let empty = EmptyStack
let rec append x y =
match x with
| Cons(hd, tl) -> Node(lazy(printfn "appending... got %A" hd; hd, append tl y))
| Nil -> y
let rec iter f = function
| Cons(hd, tl) -> f(hd); iter f tl
| Nil -> ()
maintenance.fs (main program trying to use those libraries)
///////////////// preparing the data ////////////////////
open System
open System.Collections.Generic
open System.IO
open AwesomeCollections
open AwesomeCollections.Stack
open AwesomeCollections.Heap
let stopWatch = System.Diagnostics.Stopwatch.StartNew()
let x = File.ReadAllLines "C:\Users\Fagui\Documents\GitHub\Learning Fsharp\Algo Stanford\PA 6 - median.txt"
let lowheap = new BinaryHeap<int>(compare,EmptyHeap)
let highheap = new BinaryHeap<int>(compare,EmptyHeap)
Finally if in the solution, I decide to use the following file
AwesomeCollections_bis.fs alone (no fsi file) the code will compile ok.
// this file used without the fsi file works
// but i don't know why
(* AwesomeCollections_bis.fs *)
namespace AwesomeCollections
type 'a stack =
| EmptyStack
| StackNode of 'a * 'a stack
module Stack =
let hd = function
| EmptyStack -> failwith "Empty stack"
| StackNode(hd, tl) -> hd
let tl = function
| EmptyStack -> failwith "Empty stack"
| StackNode(hd, tl) -> tl
let cons hd tl = StackNode(hd, tl)
let empty = EmptyStack
let rec rev s =
let rec loop acc = function
| EmptyStack -> acc
| StackNode(hd, tl) -> loop (StackNode(hd, acc)) tl
loop EmptyStack s
type Queue<'a>(f : stack<'a>, r : stack<'a>) =
let check = function
| EmptyStack, r -> Queue(Stack.rev r, EmptyStack)
| f, r -> Queue(f, r)
member this.hd =
match f with
| EmptyStack -> failwith "empty"
| StackNode(hd, tl) -> hd
member this.tl =
match f, r with
| EmptyStack, _ -> failwith "empty"
| StackNode(x, f), r -> check(f, r)
member this.enqueue(x) = check(f, StackNode(x, r))
static member empty = Queue<'a>(Stack.empty, Stack.empty)
type color = R | B
type 'a tree =
| E
| T of color * 'a tree * 'a * 'a tree
module Tree =
let hd = function
| E -> failwith "empty"
| T(c, l, x, r) -> x
let left = function
| E -> failwith "empty"
| T(c, l, x, r) -> l
let right = function
| E -> failwith "empty"
| T(c, l, x, r) -> r
let rec exists item = function
| E -> false
| T(c, l, x, r) ->
if item = x then true
elif item < x then exists item l
else exists item r
let balance = function (* Red nodes in relation to black root *)
| B, T(R, T(R, a, x, b), y, c), z, d (* Left, left *)
| B, T(R, a, x, T(R, b, y, c)), z, d (* Left, right *)
| B, a, x, T(R, T(R, b, y, c), z, d) (* Right, left *)
| B, a, x, T(R, b, y, T(R, c, z, d)) (* Right, right *)
-> T(R, T(B, a, x, b), y, T(B, c, z, d))
| c, l, x, r -> T(c, l, x, r)
let insert item tree =
let rec ins = function
| E -> T(R, E, item, E)
| T(c, a, y, b) as node ->
if item = y then node
elif item < y then balance(c, ins a, y, b)
else balance(c, a, y, ins b)
(* Forcing root node to be black *)
match ins tree with
| E -> failwith "Should never return empty from an insert"
| T(_, l, x, r) -> T(B, l, x, r)
let rec print (spaces : int) = function
| E -> ()
| T(c, l, x, r) ->
print (spaces + 4) r
printfn "%s %A%A" (new System.String(' ', spaces)) c x
print (spaces + 4) l
type BinaryTree<'a when 'a : comparison> (inner : 'a tree) =
member this.hd = Tree.hd inner
member this.left = BinaryTree(Tree.left inner)
member this.right = BinaryTree(Tree.right inner)
member this.exists item = Tree.exists item inner
member this.insert item = BinaryTree(Tree.insert item inner)
member this.print() = Tree.print 0 inner
static member empty = BinaryTree<'a>(E)
type 'a heap =
| EmptyHeap
| HeapNode of int * 'a * 'a heap * 'a heap
module Heap =
let height = function
| EmptyHeap -> 0
| HeapNode(h, _, _, _) -> h
(* Helper function to restore the leftist property *)
let makeT (x, a, b) =
if height a >= height b then HeapNode(height b + 1, x, a, b)
else HeapNode(height a + 1, x, b, a)
let rec merge comparer = function
| x, EmptyHeap -> x
| EmptyHeap, x -> x
| (HeapNode(_, x, l1, r1) as h1), (HeapNode(_, y, l2, r2) as h2) ->
if comparer x y <= 0 then makeT(x, l1, merge comparer (r1, h2))
else makeT (y, l2, merge comparer (h1, r2))
let hd = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> x
let tl comparer = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> merge comparer (l, r)
let rec to_seq comparer = function
| EmptyHeap -> Seq.empty
| HeapNode(h, x, l, r) as node -> seq { yield x; yield! to_seq comparer (tl comparer node) }
type 'a BinaryHeap(comparer : 'a -> 'a -> int, inner : 'a heap) =
(* private *)
member this.inner = inner
(* public *)
member this.hd = Heap.hd inner
member this.tl = BinaryHeap(comparer, Heap.tl comparer inner)
member this.merge (other : BinaryHeap<_>) = BinaryHeap(comparer, Heap.merge comparer (inner, other.inner))
member this.insert x = BinaryHeap(comparer, Heap.merge comparer (inner,(HeapNode(1, x, EmptyHeap, EmptyHeap))))
interface System.Collections.Generic.IEnumerable<'a> with
member this.GetEnumerator() = (Heap.to_seq comparer inner).GetEnumerator()
interface System.Collections.IEnumerable with
member this.GetEnumerator() = (Heap.to_seq comparer inner :> System.Collections.IEnumerable).GetEnumerator()
static member make(comparer) = BinaryHeap<_>(comparer, EmptyHeap)
type 'a lazyStack =
| Node of Lazy<'a * 'a lazyStack>
| EmptyStack
module LazyStack =
let (|Cons|Nil|) = function
| Node(item) ->
let hd, tl = item.Force()
Cons(hd, tl)
| EmptyStack -> Nil
let hd = function
| Cons(hd, tl) -> hd
| Nil -> failwith "empty"
let tl = function
| Cons(hd, tl) -> tl
| Nil -> failwith "empty"
let cons(hd, tl) = Node(lazy(hd, tl))
let empty = EmptyStack
let rec append x y =
match x with
| Cons(hd, tl) -> Node(lazy(printfn "appending... got %A" hd; hd, append tl y))
| Nil -> y
let rec iter f = function
| Cons(hd, tl) -> f(hd); iter f tl
| Nil -> ()
i can see indentation is important and I thought playing with it would solve the problem, but it didn't for me.
Thank you for anyone graciously helping !
I think that the reason why your code is not compiling is that the fsi interface file hides the constructor of BinaryHeap, so the following does not work because the constructor is private:
let highheap = new BinaryHeap<int>(compare,EmptyHeap)
The type exposes a make static member so I think you can use that instead:
let highheap = BinaryHeap.make compare
This is probably not particularly idiomatic F# design, but I guess it is mostly a sample rather than a maintained library. There might be some alternatives in FSharpX Collections library.

How to obtain a minimal key from functional dependencies?

I need some help and guidelines.
I have the following relation: R = {A, B, C, D, E, F} and the set of functional dependencies
F = {
{AB -> C};
{A -> D};
{D -> AE};
{E -> F};
}
What is the primary key for R ?
If i apply inference rules i get these additional Function dependencies:
D -> A
D -> E
D -> F
D -> AEF
A -> E
A -> F
A -> DEF
How do I continue?
There is a well known algorithm to do this. I don't remember it, but the excercise seems to be simple enough not to use it.
I think this is all about transitivity:
CurrentKey = {A, B, C, D, E, F}
You know D determines E and E determines F. Hence, D determines F by transitivity. As F doesn't determine anything, we can remove it and as E can be obtained from D we can remove it as well:
CurrentKey = {A, B, C, D}
As AB determines C and C doesn't determine anything we know it can't be part of the key, so we remove it:
CurrentKey = {A, B, D}
Finally we know A determines D so we can remove the latter from the key:
CurrentKey = {A, B}
If once you have this possible key, you can recreate all functional dependencies it is a possible key.
PS: If you happen to have the algorithm handy, please post it as I'd be glad to re-learn that :)
Algorithm: Key computation (call with x = ∅)
procedure key(x;A;F)
foreach ! B 2 F do
if x and B 2 x and B ̸2 then
return; /* x not minimal */
fi
od
if x+ = A then
print x; /* found a minimal key x */
else
X any element of A 􀀀 x+;
key(x [ fXg;A;F);
foreach ! X 2 F do
key(x [ ;A;F);
od
fi