Compiler running out of memory with polymorphically recursive function - recursion

If I try to compile the following code for adding to a fingertree, the elm compiler waits a long time and then reports that it is out of memory.
module FingerTree exposing(..)
type Node a
= Node2 a a
| Node3 a a a
type Finger a
= One a
| Two a a
| Three a a a
| Four a a a a
type FingerTree a
=Empty
|Single a
|Deep (Finger a) (FingerTree(Node a)) (Finger a)
fLeftAdd: a -> Finger a -> Finger a
fLeftAdd a0 finger =
case finger of
One a1 -> Two a0 a1
Two a1 a2 -> Three a0 a1 a2
Three a1 a2 a3 -> Four a0 a1 a2 a3
Four a1 a2 a3 a4 -> finger
leftAdd: a -> FingerTree a -> FingerTree a
leftAdd a0 fingerTree=
case fingerTree of
Empty -> Single a0
Single a1 -> Deep (One a0) Empty (One a1)
Deep left middle right ->
case left of
Four a1 a2 a3 a4 ->
Deep(Two a0 a1) ( leftAdd (Node3 a2 a3 a4) middle) right
_ -> Deep (fLeftAdd left a0) middle right
My first thought was that perhaps you just can't have polymorphic recursion (a polymorphic function calling itself with a different type signature). However this variant, replacing the custom "Finger" and "Node" types with lists, compiles fine:
module HackyTree exposing(..)
type HackyTree a
= Empty
|Single a
|Deep (List a) (HackyTree (List a)) (List a)
leftAdd: a -> HackyTree a -> HackyTree a
leftAdd a0 tree=
case tree of
Empty -> Single a0
Single a1 -> Deep [a0] Empty [a1]
Deep left middle right ->
case left of
[a1, a2, a3, a4] ->
Deep [a0, a1] ( leftAdd [a2, a3, a4] middle) right
_ -> Deep (a0::left) middle right
I'd like to get the first version working. Is this a compiler bug? Is there a recommended way to refactor to avoid this?

Are you sure your last line is _ -> Deep (fLeftAdd left a0) middle right and not _ -> Deep (fLeftAdd a0 left) middle right? If I change it everything compiles fine.
Note that the signature of fLeftAdd is fLeftAdd: a -> Finger a -> Finger a. You are pattern matching on a FingerTree a, in particular the Deep (Finger a) (FingerTree(Node a)) (Finger a) case.
With _ -> Deep (fLeftAdd left a0) middle right you're applying fLeftAdd to a left, which is a Finger a and to a0, which is an a.
You also have the constraint that the result of (fLeftAdd left a0) and right have the same type.
This means that (fLeftAdd left a0) should produce a Finger a when given a Finger a and an a as parameters, which breaks type inference since fLeftAdd: a -> Finger a -> Finger a.
This is a minimal example where the compiler doesn't go out of memory:
leftAdd: a -> FingerTree a -> FingerTree a
leftAdd a0 fingerTree=
case fingerTree of
Deep left middle right ->
Deep (fLeftAdd left a0) middle right
_ -> Single a0
I pasted it in Try Elm and I got the following error messages:
-- TYPE MISMATCH ---------------------------------------------------------------
The type annotation for leftAdd does not match its definition.
27| leftAdd: a -> FingerTree a -> FingerTree a
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The type annotation is saying:
a -> FingerTree a -> FingerTree a
But I am inferring that the definition has this type:
Finger ? -> FingerTree ? -> FingerTree (Finger ?)
Hint: A type annotation is too generic. You can probably just switch
to the type I inferred. These issues can be subtle though, so read
more about it.
https://github.com/elm-lang/elm-compiler/blob/0.17.0/hints/type-annotations.md
-- INFINITE TYPE ---------------------------------------------------------------
I am inferring a weird self-referential type for left
30| Deep left middle right ->
^^^^ Here is my best effort at writing down the type. You will see ? and ∞ for parts of the type that repeat something already
printed out infinitely.
?
Usually staring at the type is not so helpful in these cases, so
definitely read the debugging hints for ideas on how to figure this
out:
https://github.com/elm-lang/elm-compiler/blob/0.17.0/hints/infinite-type.md
I'd recommend you to try to create a simple self contained compilable example and raise an issue on the compiler project

Related

Eliminate Left Recursion in a Context Free Grammar

I understood Left Recursive Grammar (LRG) and how to remove it.
But i dont know how to remove recursive grammar which combine both left and right recursive:
A -> aAb | c
The full question is construct parsing table of LL(1) grammar of this:
S -> aABb
A -> aAb | e (epsilon)
B -> bB | c

Why is a sum (or discriminated union or disjoint union) the inverse of a product?

I'm trying to wrap my head around category theory and this question just came to my mind - why is the sum type the inverse of the product type? I mean, I see how arrows are changing directions in the opposite category, but I don't see why sum couldn't contain both components coming to it.
They are dual in the sense that one is defined by the mapping in property, and the other by the mapping out property. Every mapping into a product, c -> (a, b), is equivalent to a pair of functions c -> a and c -> b. Every mapping out of a coproduct, Either a b -> c is equivalent to a pair of functions a -> c and b -> c (think of pattern matching the Left a and Right b constructors).

Finding the full network connected with a node in neo4j

Suppose I have a neo4j graph with 3 different kind of nodes (say type A, type B, type C).
There are :
5 nodes of type A
40 nodes of type B
200 nodes of type C
Each node of type A are connecting to one or more of type B ((A -> B)) and each node of type B are connecting to one or more of type C ((B -> C)).
One node of type B can be shared by more than one type A nodes (A1 -> B1, A2 -> B1) and one node of type C can be shared by more than one type B nodes (B1 -> C1, B2 -> C1).
No node of type A connects with any node of type C. And the relationships are directional as described above.
For a given node of type A, can I find out all the nodes in the connected network, i.e., the entire tree emerging from that node, and not just the immediately connected nodes?
So basically I am looking for a py2neo function or cypher query that can give me a full tree or full network emerging from a given node.
Is this query respond to your needs ?
MATCH p=(a:A)-->(b:B)-->(c:C)
WHERE a.id = 'your id' // your condition to find your specific A node
RETURN p

Prolog - writing successive numbers_ [duplicate]

This question already has an answer here:
Hanoi Tower(Towers of Hanoi)
(1 answer)
Closed 8 years ago.
My task is this: Make this hanoi program write a successive number before it writes each sentence.
The hanoi program is this:
hanoi(N):-move(N,left,middle,right).
move(0,_,_,_):- !.
move(N,A,B,C):- M is N-1, move(M,A,C,B), inform(A,B), move(M,C,B,A).
inform(A,B):- write('MOVING DISK FROM '), write(A),write(' TO '),write(B),nl.
And I want the output to look like this:
1: MOVING DISK FROM left TO middle
2: MOVING DISK FROM left TO right
3: MOVING DISK FROM middle TO right
4: MOVING DISK FROM left TO middle
5: MOVING DISK FROM right TO left
6: MOVING DISK FROM right TO middle
7: MOVING DISK FROM left TO middle
First consider using a DCG to describe the list of moves:
hanoi(N, Moves) :- phrase(moves(N,left,middle,right), Moves).
moves(0,_,_,_) --> [].
moves(N,A,B,C) --> { N #> 0, M #= N-1 }, moves(M,A,C,B), [A->B], moves(M,C,B,A).
This lets you separate the program logic from side-effects like printing results. Once you have a list of moves, it is easy to write them, for example with:
write_moves([], _).
write_moves([From->To|Ms], N) :-
format("~w: move disk from ~w to ~w\n", [N,From,To]),
N1 #= N + 1,
write_moves(Ms, N1).
Example query and its result:
?- hanoi(3, Moves), write_moves(Moves, 1).
1: move disk from left to middle
2: move disk from left to right
3: move disk from middle to right
4: move disk from left to middle
5: move disk from right to left
6: move disk from right to middle
7: move disk from left to middle
Moves = [ (left->middle), (left->right), (middle->right), ...].
A straight-forward approach would be to use a dynamic predicate representing the line number. Using assert/retract isn't real-time friendly, but it works fine for an application like this. I reformatted your working Hanoi code for readability, and I added the lines noted with comments:
% hanoi
%
:- dynamic(line/1). % Define a dynamic predicate "line"
hanoi(N) :-
assertz(line(1)), % Assert the first line as 1
move(N, left, middle, right).
move(0, _, _, _) :- !.
move(N, A, B, C) :-
M is N-1,
move(M, A, C, B),
inform(A, B),
move(M, C, B, A).
inform(A, B) :-
line(N), % get the current line number
NextN is N + 1, % next line number will be current one plus 1
retract(line(_)), % retract the old line number
assertz(line(NextN)), % assert the next line number for next time
write(N), % write the line number
write(': '), % and a delimiter
write('MOVING DISK FROM '),
write(A),
write(' TO '),
write(B),
nl.
There are other ways to generate successive numbers, such as the following simplest case.
sequence(1).
sequence(X) :- sequence(Y), X is Y + 1.
| ?- sequence(X).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 4 ?
In some cases, something like this can be integrated in with a predicate to give you sequence numbers. Since the hanoi predicate has a tree-like recursion, I found it easier to use an assertz mechanism.

How to implement a binary heap using list in OCaml?

I am implementing a binary heap using list in OCaml, just to sharpen my OCaml skills.
I feel it very difficult using list and after struggling for 2 days, I have to come here for suggestions and hints.
Here is my thought so far
Obviously, I can't use the orignal array based algorithm to implement it using list.
What I am trying to utilise is binary tree. I have keep the invariant that a node should be bigger than any node whose level is lower than its.
I roughly figured out how to implement insert, although I am not sure whether it is correct or not.
For the binary tree, each node has two children, value and size n which is the total number of offsprings it has. This n is used to balance the tree.
When inserting x, I compare with a node (from root, recursively). Assume x < the value of the node, then
If one or both of the node's children are Leaf, then I insert the x to that Leaf place.
If none of the node's children are Leaf, then I will choose the child whose n is less and then recursively insert.
Here is my code
type 'a heap =
| Node of 'a * 'a heap * 'a heap * int
| Leaf
exception EmptyHeapException
let create_heap () = Leaf;;
let rec insert x = function
| Leaf -> Node (x, Leaf, Leaf, 0)
| Node (v, l, r, n) ->
let (stay, move) = if x > v then (x, v) else (v, x)
in
match (l, r) with
| (Leaf, Leaf) ->
Node (stay, Node (move, Leaf, Leaf, 0), Leaf, 1)
| (Leaf, _) ->
Node (stay, Node (move, Leaf, Leaf, 0), r, n+1)
| (_, Leaf) ->
Node (stay, l, Node (move, Leaf, Leaf, 0), n+1)
| (Node (_, _, _, n1), Node (_, _, _, n2)) ->
if n1 <= n2 then
Node (stay, (insert move l), r, n1+1)
else
Node (stay, l, (insert move r), n2+1);;
Ok, I have following questions.
Am I heading to the correct direction? Is my thought or implementation correct?
I get stuck in implementing get_top function. I don't know how to continue. any hints?
ocaml batteries implemented an efficient batHeap.ml. I have had a look, but I feel its way is totally different from mine and I can't understand it. Any one can help me understanding it?
This insertion code looks pretty nice to me. (I was confused by the counts for a while, but now I see they're counting the number of offspring.)
The function to remove the largest element (the root) is basically a deletion, which is always the most difficult. In essence you need to merge two trees while maintaining your invariant. I don't have time right now to work through it in detail, but I think it will turn out to be possible.
If you look in Okasaki (which you can do if you get stuck!) you'll see his trees have an extra invariant that makes it easier to do these operations. I'm pretty sure it's not something I would come up with right away. His implementation is based on an operation that merges two trees. It's used for insertion and deletion.
At a quick glance the Batteries heap code is based on "binomial trees", which are in fact a lot more complicated. They're explained in Okasaki also.
Update
Okasaki's book Purely Functional Data Structures is an elaboration of his PhD thesis. It appears that priority queues appear only in the book--sorry. If you're really interested in FP and not too strapped for cash the book is really worth owning.
As I said, your insert code looks great to me. It seems to me you actually have two invariants:
The value in a node is less than or equal to the values at the roots of its subtrees (ordering invariant).
The populations of the subtrees of a node differ by at most 1 (balance invariant).
As I said, I don't have time to verify in detail, but it looks to me like your insert code maintains the invariants and thus is O(log n).
The usefulness of this structure depends on your being able to delete the root in O(log n) while maintaining these two invariants.
The sketch of delete would be something like this:
let pop = function Leaf -> 0 | Node (_, _, _, p) -> p
let rec merge a b =
(* populations of a, b differ by at most one. pop a >= pop b *)
match a, b with
| Leaf, Leaf -> Leaf
| Leaf, _ -> b
| _, Leaf -> a
| Node (av, al, ar, ap), Node (bv, bl, br, bp) ->
if av >= bv then Node (av, merge al ar, b, ap + bp)
else Node (bv, merge al ar, insert av (delete_min b), ap + bp)
and delete_min = function
| Leaf -> Leaf
| Node (_, Leaf, Leaf, _) -> Leaf
| Node (_, l, Leaf, _) -> l
| Node (_, Leaf, r, _) -> r
| Node (_, l, r, _) ->
if pop l >= pop r then merge l r else merge r l
I still don't have a lot of time, so this might need some fixing up for correctness or for complexity.
Update
Being a purely cerebral guy, I (truly) never wondered what Chris Okasaki is like in real life. He teaches at West Point, and it's not too difficult to find his personal page there. It might satisfy some of your curiosity.

Resources