Clourescript: converting array access - clojure

Problem
I am trying to convert the following piece of code: https://github.com/mdn/webgl-examples/blob/gh-pages/tutorial/glUtils.js#L13-L15
The JavaScript code is:
Matrix.Translation = function (v)
{
// ignore length 2 case for simplicty
if (v.elements.length == 3) {
var r = Matrix.I(4);
r.elements[0][3] = v.elements[0];
r.elements[1][3] = v.elements[1];
r.elements[2][3] = v.elements[2];
return r;
}
throw "Invalid length for Translation";
}
Now, I can rewrite it cljs as follows:
(defn translation [x y z]
(let [r (. js/Matrix I 4)]
r[0][3] = x ;; how do I write this?
r[1][3] = y ;; how do I write this?
r[2][3] = z ;; how do I write this?
))
Question
However, how do I write r[0][3] in cljs?

You can use aget and aset to work with Javascript arrays:
(def arr (array (array "a1" "a2") (array "b1" "b2") (array "c1" "c2")))
It creates following nested array:
#js [#js ["a1" "a2"] #js ["b1" "b2"] #js ["c1" "c2"]]
You can access nested elements with aget:
(aget arr 1 0)
;; => "b1"
And update with aset:
(aset arr 1 0 "newb1")
updates arr to:
#js [#js ["a1" "a2"] #js ["newb1" "b2"] #js ["c1" "c2"]]
You might want to take a look at other functions related to Javascript arrays: alength, array, make-array, array?.

Related

Add object to a list in clojure and return

I am new to functional programming and have a use case where I have a list of Books, I want to iterate over it, do some mapping and return a new List.
My code
(defn map-book [books]
((doseq [x books]
(let [lst (create-response x)]
(println "data -> " (json/encode lst))
(json/encode lst)))))
(defn create-response [book]
(let [updated-book (merge {"book-name" (.getBookName book)
"book-page" (.getBookPageCount book)}]
updated-book))
when I try to run this, I am able to get json decoded response in terminal due to println but not the json list as a response from the function.
have been stucked around for some time on this.
What I want is something like :
[{
"book-name": "rick boy",
"book-page": 110
},
{
"book-name": "poor boy",
"book-page": 124
}
]
but am getting something like, when I run my unit test:
#object[book_service.book$map_book 0x7915bca3 [book_service.book$map_book#7915bca3]
thanks for any help!
If you want to return new list (or vector), you should avoid doseq (which is for side effects- for example, printing, and always returns nil) and use map or for instead.
I guess you want to return JSON string for given data and your json library is actually Cheshire:
Dependencies: [cheshire "5.11.0"]
Require in ns: [cheshire.core :as json]
Book class:
public class Book {
String bookName;
Long pageCount;
public Book(String name, Long pages) {
bookName = name;
pageCount = pages;
}
public String getBookName() {
return bookName;
}
public Long getBookPageCount() {
return pageCount;
}
}
Clojure code:
(defn get-book-map [book]
{"book-name" (.getBookName book)
"book-page" (.getBookPageCount book)})
(defn encode-books [books]
(json/encode (map get-book-map books)))
Test:
(encode-books [(Book. "rick boy" 110)
(Book. "poor boy" 124)])
=> "[{\"book-name\":\"rick boy\",\"book-page\":110},{\"book-name\":\"poor boy\",\"book-page\":124}]"
(json/decode *1)
=> ({"book-name" "rick boy", "book-page" 110} {"book-name" "poor boy", "book-page" 124})

Easiest way to get an error message as a string in Instaparse?

Instaparse can pprint nice error messages to the REPL
=> (negative-lookahead-example "abaaaab")
Parse error at line 1, column 1:
abaaaab
^
Expected:
NOT "ab"
but I can not find a built-in function to get the message as a String. How to do that?
You could always wrap it using with-out-str:
(with-out-str
(negative-lookahead-example "abaaaab"))
You may also be interested in using with-err-str documented here.
(with-err-str
(negative-lookahead-example "abaaaab"))
I can't remember if instaparse writes to stdout or stderr, but one of those will do what you want.
Let's look at the return type of parse in the failure case:
(p/parse (p/parser "S = 'x'") "y")
=> Parse error at line 1, column 1:
y
^
Expected:
"x" (followed by end-of-string)
(class *1)
=> instaparse.gll.Failure
This pretty printing behavior is defined like this in Instaparse:
(defrecord Failure [index reason])
(defmethod clojure.core/print-method Failure [x writer]
(binding [*out* writer]
(fail/pprint-failure x)))
In the REPL this prints as a helpful human-readable description, but it can also be treated as a map:
(keys (p/parse (p/parser "S = 'x'") "y"))
=> (:index :reason :line :column :text)
(:reason (p/parse (p/parser "S = 'x'") "y"))
=> [{:tag :string, :expecting "x", :full true}]
And you could do this:
(with-out-str
(instaparse.failure/pprint-failure
(p/parse (p/parser "S = 'x'") "y")))
=> "Parse error at line 1, column 1:\ny\n^\nExpected:\n\"x\" (followed by end-of-string)\n"
Or write your own version of pprint-failure that builds a string instead of printing it.

Convert nested vector maps in clojure

I need to collect and transfer :c/name values into nested vector to first level same way.
Input example:
[:a/name "name" :a/vals [{:b/val [{:c/name "one"}{:c/name "two"}]}
{:b/val [{:c/name "three"}]}]]
Output:
[:a/name :a/vals "one, two, three"]
This produces the output from the input, is this what you want?
(defn f [[k1 _ k2 rels]]
[k1 k2
(clojure.string/join ", "
(map :c/name (apply concat (mapcat vals rels))))])

SML - Find occurences in lists to form ordered pairs

I'm trying to write a function in SML that takes in a list of ints and will output a list of ordered pairs of ints. The ordered pairs first int is the int that occurred in the input list and the second int in the ordered pair is the number of times it occurred in the input list. Also the list returned should be in ascending order according to the first int in the ordered pairs.
For example input list [1, 1, 1, 2, 3, 3, 5] would output as [(1,3), (2, 1), (3, 2), (5, 1)].
So far I have a function that uses foldl
UPDATED the code since original post.
fun turnIntoPairs l = foldl (fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)]) [] l;
I'm having trouble updating the list where I find the ordered pair that is already in the list - I want to add one to the second int in the ordered pair that was found while it's still in the list.
Any help would be greatly appreciated!
C:\Program Files (x86)\SMLNJ\\bin\.run\run.x86-win32.exe: Fatal error -- Uncaught exception Error with 0
raised at ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
[autoloading done]
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.87 Error: unbound variable or constructor: x
C:\Users\Localadmin\Desktop\CS 671\Program 3\commonFactors.sml:1.44-1.110 Error: types of if branches do not agree [literal]
then branch: int
else branch: (''Z * int) list
in expression:
if (List.exists (fn <pat> => <exp>)) a
then <errorvar> + 1
else a # (e,1) :: nil
[Finished in 0.5s with exit code 1]
Not really sure how to fix your current program, but you can solve this problem by splitting it in two: grouping equal elements and then ordering the list.
(* Groups successive equal elements into a tuples (value, count) *)
fun group (l as (x :: _)) =
let val (firstGroup, rest) = List.partition (fn y => x = y) l
in
(x, List.length firstGroup) :: (group rest)
end
| group [] = []
(* Now that we have our elements grouped, what's left is to order
them as required. *)
fun turnIntoPairs xs =
ListMergeSort.sort (fn ((x, _), (y, _)) => x >= y) (group xs)
Let's just look at the function you're passing to foldl:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then x + 1 else a # [(e, 1)])
The first problem (which the type-checker is complaining about) is that your if expression returns either x + 1, or a # [(e, 1)], which seems problematic on account of the former being a value of type int and the latter being of type (int * int) list.
Let's rewrite your code using some helper functions that I won't define and see if it gets clearer:
(fn (e, a) => if List.exists (fn (x, _) => x = e) a then increment a e else a # [(e, 1)])
Where increment has the type (int * int) list -> int -> (int * int) list.
Can you implement increment?
Like Gian, I would prefer to divide this into two functions: One that folds and one helper function that inserts. Incidentally, the insert function would take an element and an existing (int * int) list just as the accumulator function that fold accepts these two arguments.
Normally I would write an insert function curried (i.e. insert x xs) but if I write it uncurried (i.e. insert (x, xs)), I can pass it directly to foldl:
fun insert (x, []) = [(x,1)]
| insert (x, ((y,c)::xs)) =
if x = y then (y,c+1)::xs else (y,c)::insert (x, xs)
fun turnIntoPairs xs = foldl insert [] xs

wrapping knockout.js using clojurescript

I'm trying to wrap knockout.js in clojurescript but its turning to be very difficult. The problem that I'm having is the reference to the 'this' variable. I'm thinking of giving up and just using javascript directly.
I've taken examples off http://knockoutjs.com/examples/helloWorld.html and http://knockoutjs.com/examples/contactsEditor.html
I've managed to wrap easy functions with some macros. For example:
var ViewModel = function() {
this.firstName = ko.observable("Bert");
this.lastName = ko.observable("Bertington");
this.fullName = ko.computed(function() {
// Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
return this.firstName() + " " + this.lastName();
}, this);
};
becomes:
(defviewmodel data
(observing :first_name "Bert")
(observing :last_name "Bertington")
(computing :name [:first_name :last_name]
(str :first_name " " :last_name)))
However, for something harder like:
var BetterListModel = function () {
this.itemToAdd = ko.observable("");
this.allItems = ko.observableArray(["Fries", "Eggs Benedict", "Ham", "Cheese"]); // Initial items
this.selectedItems = ko.observableArray(["Ham"]); // Initial selection
this.addItem = function () {
if ((this.itemToAdd() != "") && (this.allItems.indexOf(this.itemToAdd()) < 0)) // Prevent blanks and duplicates
this.allItems.push(this.itemToAdd());
this.itemToAdd(""); // Clear the text box
};
this.removeSelected = function () {
this.allItems.removeAll(this.selectedItems());
this.selectedItems([]); // Clear selection
};
this.sortItems = function() {
this.allItems.sort();
};
};
ko.applyBindings(new BetterListModel());
I'm not sure what I can do in clojurescript to match code like this: this.allItems.push(this.itemToAdd())
Any thoughts?
After lots of trial and error, I figured out how to have the same structure for clojurescript as for javascript.
The this-as macro has a few idiosyncrasies and only works when the method is put into the class
for example I want to create something that looks like this in javascript:
var anobj = {a: 9,
get_a: function(){return this.a;}};
I have to do a whole lot more coding to get the same object in clojurescript:
(def anobj (js-obj))
(def get_a (fn [] (this-as me (.-a me))))
(aset anobj "a" 9)
(aset anobj "get_a" get_a)
which is seriously ugly for a language as beautiful as clojure. Things get worse when you have got functions that link to each other, like what happens in knockout.
I found that the best way to create an js-object with lots of this's in there is to define a __init__ method, add it to the class and then run it, then remove it from the class. For example, if I wanted to make another object:
var avobj = {a: this,
b: 98,
c: this.a
get_a: function(){return str(this.a) + str(this.c);}};
written as clojurescript with and __init__ method looks like this:
(def avobj (js-obj))
(def av__init__
#(this-as this
(aset this "a" this)
(aset this "b" 9)
(aset this "c" (.-a this))
(aset this "get_a" (fn [] (str (.-a this) (.-c this))))))
(aset avobj "__init__" av__init__)
(. avobj __init__)
(js-delete stuff "__init__")
There's still a whole bunch more code than javascript... but the most important thing is that you get the same object as javascript. Setting all the variables using this form also allows the use of macros to simplify. So now I have defined a macro:
(defmacro defvar [name & body]
(list 'do
(list 'def name
(list 'map->js
{
:__init__
(list 'fn []
(list 'this-as 'this
(list 'aset 'this "a" "blah")))
}))
;(. js/console log ~name)
(list '. name '__init__)
(list 'js-delete name "__init__")))
and with map->js taken from jayq.utils:
(defn map->js [m]
(let [out (js-obj)]
(doseq [[k v] m]
(aset out (name k) v))
out))
Now I can write code like this:
(defvar avobj
a this
b 9
c (.-a this)
get_a (fn [] (str (.-a this) (.-c this))))
and for the answer to knockout:
(defvar name_model
first_name (observable "My")
last_name (observable "Name")
name (computed (fn [] (str (. this first_name) " " (. this last_name)))))
(. js/ko (applyBindings name_model));
Which is really nice for me as it matches javascript really well and its entirely readable!
If you need an explicit reference to JavaScript's this dynamic binding, ClojureScript provides a this-as macro:
https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/core.clj#L324