I'm working through Oleg Kiselyov's tutorial Reconciling Abstraction with High Performance: A MetaOCaml approach. One exercise (exercise 23) asks for a let-insertion to bind an array index access to a local variable.
The function of question is vmult_ca, which generates code for multiplying arrays of complex numbers:
let vmult_ca :
(float_complex array -> float_complex array -> float_complex array -> unit)
code =
.<fun vout v1 v2 ->
let n = Array.length vout in
(* vector representations *)
.~(let vout = OVec (.<n>., fun i v ->
.<vout.(.~i) <- .~(of_code_complex v)>.) in
let v1 = Vec (.<n>., fun i ->
of_complex_code .<v1.(.~i)>.) in
let v2 = Vec (.<n>., fun i ->
of_complex_code .<v2.(.~i)>.) in
let module V = VMULT(FloatCodeComplex)(VecDyn) in
V.vmult vout v1 v2)
>.
;;
Where vout is the output vector that store the result.
Vec (n, fun i -> v) is an abstract vector where n is the length and fun i -> v maps each index to a value.
OVec (n, fun i v -> body) is an abstract "output vector" where n is the length and fun i v -> body runs on each index i and the associated output element v at i.
of_complex_code converts a complex code value to a code complex value, e.g. .<{real=1.0, imag=0.0}>. to {real=.<1.0>., imag=.<0.0>.}.
The module VMULT defines (point-wise) vector multiplication (see the code here for details).
When run, vmult_ca generates the following code:
val vmult_ca :
(float_complex array -> float_complex array -> float_complex array -> unit)
code = .<
fun vout_4 ->
fun v1_5 ->
fun v2_6 ->
let n_7 = Array.length vout_4 in
for i_8 = 0 to n_7 - 1 do
vout_4.(i_8) <-
{
Cmplx.im =
(((v1_5.(i_8)).Cmplx.re *. (v2_6.(i_8)).Cmplx.im) +.
((v1_5.(i_8)).Cmplx.im *. (v2_6.(i_8)).Cmplx.re));
Cmplx.re =
(((v1_5.(i_8)).Cmplx.re *. (v2_6.(i_8)).Cmplx.re) -.
((v1_5.(i_8)).Cmplx.im *. (v2_6.(i_8)).Cmplx.im))
}
done>.
Note v1_5.(i_8) is repeated 4 times. The challenge is to insert a let somewhere in vmult_ca to bind v1_5.(i_8) to a local variable to avoid the repetition. I was able to "cheat" by simply calling genlet on .<v1.(~i)>., but I have no clue where to insert the let without genlet; any hint would be appreciated.
Let-insertion is a primitive operation in BER, that automatically binds the passed code to a freshly generated variable.
Here is a working example, suppose you have the code that returns a square of an array element,
let power_elt xs i = xs.(i) * xs.(i)
and we want to generate an optimized code that has only one array access
let power_elt xs i = let x = xs.(i) in x*x
In the MetaOCaml style we can use genlet for that
let power_elt xs i =
let x = genlet .<xs.(i)>. in
.<.~x * .~x>.
The generated code for
let t = power_elt [|1;2;3|] 1;;
will be
val t : int code = .<let lv_8 = Stdlib.Array.get (* CSP xs *) 1 in lv_8 * lv_8>.
For example, if I have a list of tuples such as
[("a1", ["a2", "a3"]), ("b1", ["b2", "b3"])]
and I want to add a4 using a1 & a4 as an input to update the list so that we get
[("a1", ["a2", "a3", "a4"]), ("b1", ["b2", "b3"])] as an output, how would I go about approaching this? I know that we can't literally "update" a tuple, and that I have to make an entirely new list
You can make this function using recursion:
updateValueUsingKey :: Eq a => a -> b -> [(a, [b])] -> [(a, [b])]
updateValueUsingKey a b ((a',bs):abs)
| a == a' = (a',bs++[b]):abs -- update value if found
| otherwise = (a',bs) : updateValueUsingKey a b abs -- otherwise keep on recursing
updateValueUsingKey a b [] = [] -- end the recursion if no more elements
If you cannot mutate a List (updating existing elements) then fmap it.
If you cannot mutate a List (shrinking or expanding) then bind it.
import Data.Maybe (fromJust)
-- lookup will scan the List of Tuples for the Key
-- Use Maybe since You dont know the Key you are looking may Exist or not
updateValueUsingKey :: Eq a => a -> b -> [(a, [b])] -> Maybe [(a, [b])]
updateValueUsingKey key value associatedList =
((++[value]) <$> lookup key associatedList)
>>= (\v -> return $ fmap (\p -> if (fst p) == key then (key, v) else p) associatedList)
-- If you know exactly the key exists then use fromJust to extract the Value out of Maybe
updateValueUsingKey' :: Eq a => a -> b -> [(a, [b])] -> [(a, [b])]
updateValueUsingKey' key value associatedList = fromJust $ updateValueUsingKey key value associatedList
What you have is known as an association list: each tuple consists of a name and a value associated with that name. If all you mean to do is look up lists by their "name" (the first element of a tuple), the built-in lookup function is sufficient. Since you want to update the lists, it would be easier to work with a Map instead , which (assuming all the names are unique) can be initialized from your list easily.
import qualified Data.Map as M
type MyMap = M.Map String [String]
append :: String -> String -> MyMap -> MyMap
append k v = M.insertWith (flip (++)) k [v]
The function argument to insertWith is called with the new value as its first argument and the existing value as the second. As such, (++) alone would prepend your new element to the list. Since you want to append the new value, use flip (++) to reverse the order of the arguments.
For example:
> data = M.fromList [("a1", ["a2", "a3"]), ("b1", ["b2", "b3"])]
> data
fromList [("a1",["a2","a3"]),("b1",["b2","b3"])]
> append "a1" "a4" data
fromList [("a1",["a2","a3","a4"]),("b1",["b2","b3"])]
This compiles in Dart:
var data = ["abcd", 34, "ef", false];
int n = data[1];
print(n*2); // -> 68
I thought that list elements should be all of same type. And there is not implicit conversion from int to string or from bool to string in A):
print(data[1] is int); // -> true
print(data[3] is bool); // -> true
print(data[1] is String); // -> false
EDIT: as Mattia pointed out the real error in the following lines is not related to swapping elements in the list initializatione but to copy/paste from A) to B) leaving the same index ([1])
And this does not compile ("abcd" swapped with 34):
var data = [34, "abcd", "ef", false]; // -> type error
int n = data[1]; //EDIT: this is a non sense, should be data[0] (no error generated)
print(n*2);
Reproducible DartPad
Why? Some sort of substitution principle at work?
If you want list to accept only one type you need to add a generic type for example:
var data = <int>["abcd", 34, "ef", false]; // -> Error
by default if you don't add one the "most common type" (in this case Object) will be used and it will accept all variable types.
The second example does compile but gives a run-time error because data[1] is not an int but a String
is it possible to define a circular list in erlang?
http://en.wikipedia.org/wiki/Linked_list
first question would be what exactly a circular list mean in erlang?
is it with two elements, one element its self and next to it address to the next element, stored in a list?
if so i can say there is a possibility of defining a circular list in erlang.
but i need clarification weather is it what i think a circular list is in erlang?
There is no built-in list mechanism to do it. However, you can build one using a tuple holding the elements you've visited or not.
The basic structure is a tuple with two lists: {Old, New}. When you first start with an empty list, it looks like {[],[]}. When you fill the list, you fill it in the New list:
new() -> {[], []}.
insert(X, {Old, New}) -> {Old, [X|New]}.
peek({_Old, [H|_]}) -> X.
To move within the list, what you do is first seek in the New list, and put the value in the old one:
next({Old, [H|New]}) -> {[H|Old], New}.
That's fine and it works as if we were just discarding old elements. What happens when we hit the end of the list though? We need to fix the function (and also the peek one):
peek({Old, []}) -> hd(lists:reverse(Old));
peek({_Old, [H|_]}) -> X.
next({Old, []}) ->
{[], lists:reverse(Old)}}.
next({Old, [H|New]}) ->
{[H|Old], New}}.
If there's nothing in the list, it crashes. You could also return 'undefined' if you wanted to by special casing it:
next({[], []}) ->
undefined;
next({Old, []}) ->
{[], lists:reverse(Old)}.
next({Old, [H|New]}) ->
{[H|Old], New}.
This then lets you use the function 'next', 'peek' and possibly 'delete' (see below) to do normal stuff. We could also add a 'prev' function to allow backwards browsing:
prev({[], []}) ->
undefined;
prev({[], New}) ->
{lists:reverse(New), Old}.
prev({[H|Old], New}) ->
{Old, [H|New]}.
delete({Old, []}) -> {[], tl(lists:reverse(Old))};
delete({Old,[H|New]}) -> {Old, New};
And that should cover most of it.
Seeing erlang, and the erlang virtual machine, only supports immutable data it is impossible to build a circular list. If you were to build one yourself in some "illegal" way then it is not certain that the memory management could handle it properly.
There are no circular lists in Erlang supported by the virtual machine. You have to build them yourself if you want one.
Why yes you can ;)
14> X = ll:new().
20496
15> ll:push(X, 1).
1
16> ll:push(X, 2).
2
17> ll:push(X, 3).
3
18> ll:pop(X).
3
19> ll:hd(X).
2
20> {V0,R0} = ll:first(X).
{2,#Ref<0.0.0.80>}
21> {V1,R1} = ll:next(X, R0).
{1,#Ref<0.0.0.76>}
22> {V2,R2} = ll:next(X, R1).
{2,#Ref<0.0.0.80>}
And here is some crappy code to prove it
-module(ll).
-export([new/0, delete/1, push/2, pop/1, first/1, hd/1, next/2]).
-define (META_KEY, '$meta_list').
-record(elt, {id, val, next}).
-record(meta, {id =?META_KEY, size, hd, tl}).
% Returns TID of ETS table representing linked list
new() ->
Tid = ets:new(alist,[{keypos, 2}]),
ets:insert(Tid, #meta{size=0, hd=undefined, tl=undefined}),
Tid.
% Delete list / ETS table representing linked list
delete(AList) ->
ets:delete(AList).
% Returns the value of what was pushed
push(AList, AnElt) ->
#meta{size = Size} = Meta = get_meta(AList),
Hd = get_head(AList, Meta),
Ref = make_ref(),
NewElt = #elt{id=Ref, val=AnElt, next=iif(Size, 0, Ref, Hd#elt.id)},
ets:insert(AList, NewElt),
case Size of
0 -> ets:insert(AList, Meta#meta{size=1,hd=Ref,tl=Ref});
N ->
Tl = get_tail(AList, Meta),
ets:insert(AList, Tl#elt{next = Ref}),
ets:insert(AList, Meta#meta{size=N+1,hd=Ref})
end,
AnElt.
% Returns the value of the popped element
pop(AList) ->
#meta{size = Size} = Meta = get_meta(AList),
Hd = get_head(AList, Meta),
case Size of
0 -> ok;
1 ->
ets:insert(AList, Meta#meta{size=0, hd=undefined,tl=undefined});
N ->
Next = get_next(AList, Hd),
Tail = get_tail(AList, Meta),
ets:insert(AList, Meta#meta{size=N-1, hd=Next#elt.id}),
ets:insert(AList, Tail#elt{next=Next#elt.id})
end,
ets:delete(AList, Hd#elt.id),
Hd#elt.val.
% Returns the value of the first element
hd(AList)->
{First, _Next} =first(AList),
First.
% Returns {val, ptr_to_tail}. The prt_to_tail can be used in next/2
first(AList)->
#meta{size = Size} = Meta = get_meta(AList),
if
Size == 0 -> {undefined, undefined};
true ->
Hd = get_head(AList, Meta),
{Hd#elt.val, Hd#elt.id}
end.
% Given ptr_to_tal, returns {hd(tail), ptr_to_tail}.
next(_AList, undefined) ->
{undefined, undefined};
next(AList, Id) ->
case ets:lookup(AList, Id) of
[] -> {error, node_missing};
[#elt{next=Next}] ->
case ets:lookup(AList, Next) of
[]-> {error, node_missing};
[#elt{val=Value}] ->
{Value, Next}
end
end.
%helper functions
get_meta(List)->
case ets:lookup(List, ?META_KEY) of
[] -> {error, corruptlist};
[Meta] -> Meta
end.
get_head(AList, #meta{size = Size, hd=Hd} ) ->
case Size of
0 -> #elt{};
_N ->
case ets:lookup(AList, Hd) of
[] -> {error, corruptlist};
[Head] -> Head
end
end.
get_tail(AList, #meta{size = Size, tl=Tl} ) ->
case Size of
0 -> #elt{};
_N ->
[Tail] = ets:lookup(AList, Tl),
Tail
end.
get_next(_AList, #elt{next=undefined}) -> #elt{};
get_next(AList, #elt{next=Next}) ->
case ets:lookup(AList, Next) of
[] -> {error, corruptlist};
[Elt] -> Elt
end.
iif(A, B, TruePart, ElsePart)->
case A == B of
true -> TruePart;
false -> ElsePart
end.
As pointed out above, you would have to implement them yourself. But as you can associate data to other data in various ways in erlang there is nothing stopping you from doing so.
Essentially you need just one thingie representing the current index and another one representing the pointer to the next index. One funny way would be starting a process for each element in the list pointing to the next(or previous) process(element) by its PID. One (or many) special purpose process(es) could be crawling those other "list"-processes. Less crazy aproaches might make use of ets or mnesia.
I have a function compute a list to boolean matrix where num_of_name: 'a list -> 'a -> int : return a position of element in a list.
1) I would like mat_of_dep_rel : 'a list -> bool array array.
My problem is that from the first List.iter it should take a list l and not an empty list []. But if I return l instead of [], it will give me a type: ('a * 'a list) list -> boolean array array. Which is not what I want.
I would like to know how can I return mat_of_dep_rel: 'a list -> bool array array?
let mat_of_dep_rel l =
let n = List.length l in
let m = Array.make_matrix n n false in
List.iter (fun (s, ss) ->
let i = num_of_name ss s in
List.iter (fun t ->
m.(i).( num_of_name ss t) <- true) ss) [];
m;;
2) I have another functions compute equivalence classes, to compute an equivalence class : check an element i if it has a path i -> j and j -> i or itself. I would like it return for me a type int list list. In this code I force the return type 'list list by put j in [j]. My question is:
Is it correct if I force like that? If not how can I return the type I want int list list.
let eq_class m i =
let mi = m.(i) in
let aux =
List.fold_right (fun j l ->
if j = i || mi.(j) && m.(j).(i) then
[j] :: l else l) in
aux [] [];;
Another function eq_classes compute a set of equivalence classes by collect all the equivalence class. I would like to use a list data structure more than using a set. But for the moment, I am not really understand about the code saying here.
Could you please explain for me? If I want to use a list data structure, how can I use it? What is a different between a list and a set data structure in OCaml? Advance/Disadvance of its?
let eq_classes m =
IntSet.fold (fun i l -> IntMap.add i (eq_class m i) l)
IntSet.empty IntMap.empty;;
3) My last question is that. After having all the equivalence classes I would like to sort them. I have another functions
let cmp m i j = if eq_class m i = eq_class m j then 0
else if m.(i).(j) then -1 else 1;;
let eq_classes_sort m l = List.sort (cmp m) l;;
for the last function I want it return for me bool array array -> int list list not bool array array -> int list -> int list
Thank you for your help.
There are quite many things wrong or obscure about your questions, but I'll try to answer as well as possible.
Question 1
You're apparently trying to transform the representation of a dependency graph from a list to a matrix. It does not make any kind of sense to have a dependency graph represented as 'a list (in fact, there is no interesting way to build a boolean matrix from an arbitrary list anyway) so you probably intended to use an (int * int) list of pairs, each pair (i,j) being a dependency i -> j.
If you instead have a ('a * 'a) list of arbitrary pairs, you can easily number the elements using your num_of_name function to turn it into the aforementioned (int * int) list.
Once you have this, you can easily construct a matrix :
let matrix_of_dependencies dependencies =
let n = List.fold_left (fun (i,j) acc -> max i (max j acc)) 0 dependencies in
let matrix = Array.make_matrix (n+1) (n+1) false in
List.iter (fun (i,j) -> matrix.(i).(j) <- true) dependencies ;
matrix
val matrix_of_dependencies : (int * int) list -> bool array array
You can also compute the parameter n outside the function and pass it in.
Question 2
An equivalence class is a set of elements that are all equivalent. A good representation for a set, in OCaml, would be a list (module List) or a set (module Set). A list-of-lists is not a valid representation for a set, so you have no reason to use one.
Your algorithm is obscure, since you're apparently performing a fold on an empty list, which will just return the initial value (an empty list). I assume that you intended to instead iterate over all entries in the matrix column.
let equivalence_class matrix element =
let column = matrix.(element) and set = ref [] in
Array.iteri begin fun element' dependency ->
if dependency then set := element' :: !set
end column ;
!set
val equivalence_class : bool array array -> int list
I only check for i -> j because, if your dependencies are indeed an equivalence relationship (reflexive, transitive, symmetrical), then i -> j implies j -> i. If your dependencies are not an equivalence relationship, then you are in fact looking for cycles in a graph representation of a relationship, which is an entirely different algorithm from what you suggested, unless you compute the transitive closure of your dependency graph first.
Sets and lists are both well-documented standard modules, and their documentation is freely available online. Ask questions on StackOverflow if you have specific issues with them.
You asked us to explain the piece of code you provide for eq_classes. The explanation is that it folds on an empty set, so it returns its initial value - an empty map. It is, as such, completely pointless. A more appropriate implementation would be:
let equivalence_classes matrix =
let classes = ref [] in
Array.iteri begin fun element _ ->
if not (List.exists (List.mem element) !classes) then
classes := equivalence_class matrix element :: !classes
end matrix ;
!classes
val equivalence_classes : bool array array -> int list list
This returns all the equivalence classes as a list-of-lists (each equivalence class being an individual list).
Question 3
The type system is pointing out that you have defined a comparison function that works on int, so you can only use it to sort an int list. If you intend to sort an int list list (a list of equivalence classes), then you need to define a comparison function for int list elements.
Assuming that (as mentioned above) your dependency graph is transitively closed, all you have to do is use your existing comparison algorithm and apply it to arbitrary representants of each class:
let compare_classes matrix c c` =
match c, c` with
| h :: _, h' :: _ -> if matrix.(h).(h') then 1 else -1
| _ -> 0
let sort_equivalence_classes matrix = List.sort (compare_classes matrix)
This code assumes that 1. each equivalence class only appears once and 1. each equivalence class contains at least one element. Both assumptions are reasonable when working with equivalence classes, and it is a simple process to eliminate duplicates and empty classes beforehand.