Why is trim() not working inside map in Clojure? - clojure

user=> (.trim " kkk ")
"kkk"
user=> (map .trim ["jjj " " llll" " o "] )
CompilerException java.lang.RuntimeException: Unable to resolve symbol: .trim in this context, compiling:(NO_SOURCE_PATH:1:1)
Any explanation for this behavior ?
I ended up using clojure.string/trim. but wanted to know, whats the prob here ?

You need to wrap .trim in an anonymous function so map gets a first-class function instead of a member function:
(map #(.trim %) ["jjj " " llll" " o "])
Alternatively, you could use memfn to create this first-class function for you:
(map (memfn trim) ["jjj " " llll" " o "])

This works:
(map #(.trim %) ["jjj " " llll" " o "] )
So I guess .trim is some sort syntactic sugar that doesn't have a meaning outside forms?

You can't use a member function like that. It's not a Clojure function. Easiest way is to use a closure.
(map #(.trim %) [" aa " " bb "])
You can also convert a member function to a Clojure function with memfn.

Related

How to join two utf8 strings together in Clarity?

In my Clarity smart contract, I am trying to to append one string ("Hello") to another string (" to Clarity Language"). Both strings are of type string-utf8.
Deploying the contract below fails with an error: expecting expression of type \'(string-utf8 100)\', found \'(string-utf8 120)\'
(define-data-var a-string (string-utf8 100) u"Hello")
(var-set a-string (concat (var-get a-string) u" to Clarity Language"))
(print (var-get a-string))
How to make this work?
concat does not optimize the resulting string. The new string is of type string-utf8 with length 120, adding the length of the variable type to the length of the other string (100 + 20).
You have to wrap the concat call with a as-max-len?:
(define-data-var a-string (string-utf8 100) u"Hello")
(var-set a-string
(unwrap! (as-max-len?
(concat (var-get a-string) u" to Clarity Language") u100) (err "text too long")))
(print (var-get a-string))
Note, that the type length is defined by an int (100), while as-max-len? takes a uint parameter (u100).

Clojure - Get Realtime Updates with Cloud Firestore

Here is EventListener interface
package com.google.cloud.firestore;
public interface EventListener <T> {
void onEvent(#javax.annotation.Nullable T t, #javax.annotation.Nullable com.google.cloud.firestore.FirestoreException e);
}
Here is the Java section code
(refer to https://firebase.google.com/docs/firestore/query-data/listen)
DocumentReference docRef = db.collection("cities").document("SF");
docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
#Override
public void onEvent(#Nullable DocumentSnapshot snapshot,
#Nullable FirestoreException e) {
if (e != null) {
System.err.println("Listen failed: " + e);
return;
}
if (snapshot != null && snapshot.exists()) {
System.out.println("Current data: " + snapshot.getData());
} else {
System.out.print("Current data: null");
}
}
});
Here is my converted code to Clojure
(defn outlook-synced-listenning
[^DocumentReference ref]
(let []
(-> ref
(.addSnapshotListener
(reify EventListener
(^void onEvent [this ^DocumentSnapshot snapshot ^FirestoreException e]
(if-not (nil? e)
(println " Listen failed: " + e)
)
(if (and (not (nil? snapshot)) (.exists snapshot))
(println " Current data: " + (.getData snapshot))
(println " Current data null ")
)
)))
)
))
Here is the error
Caused by: java.lang.IllegalArgumentException: Can't find matching method: onEvent, leave off hints for auto match.
at clojure.lang.Compiler$NewInstanceMethod.parse(Compiler.java:8305)
at clojure.lang.Compiler$NewInstanceExpr.build(Compiler.java:7853)
at clojure.lang.Compiler$NewInstanceExpr$ReifyParser.parse(Compiler.java:7754)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6919)
I think the error with parameter types and type hints when the Clojure code does not match with Java interface.
I guess that I don't still convert correctly the code line below to Clojure
docRef.addSnapshotListener(new EventListener < DocumentSnapshot > ()
Please advise me how I do. Thank you
I removed all paramater types and type hints except for "this". It works fine
Many thanks to Frank Moyer
(defn outlook-synced-listenning
[^DocumentReference ref]
(let []
(-> ref
(.addSnapshotListener
(reify EventListener
(onEvent [this snapshot e]
(if-not (nil? e)
(println " Listen failed: " + e)
)
(if (and (not (nil? snapshot)) (.exists snapshot))
(println " Current data: " + (.getData snapshot))
(println " Current data null ")
)
)))
)
))

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))))])

Looking for a replace-in-string function in elisp

I'm looking for an equivalent of replace-regexp-in-string that just uses literal strings, no regular expressions.
(replace-regexp-in-string "." "bar" "foo.buzz") => "barbarbarbarbarbarbarbar"
But I want
(replace-in-string "." "bar" "foo.buzz") => "foobarbuzz"
I tried various replace-* functions but can't figure it out.
Edit
In return for the elaborate answers I decided to benchmark them (yea, I know all benchmarks are wrong, but it's still interesting).
The output of benchmark-run is (time, # garbage collections, GC time):
(benchmark-run 10000
(replace-regexp-in-string "." "bar" "foo.buzz"))
=> (0.5530160000000001 7 0.4121459999999999)
(benchmark-run 10000
(haxe-replace-string "." "bar" "foo.buzz"))
=> (5.301392 68 3.851943000000009)
(benchmark-run 10000
(replace-string-in-string "." "bar" "foo.buzz"))
=> (1.429293 5 0.29774799999999857)
replace-regexp-in-string with a quoted regexp wins. Temporary buffers do remarkably well.
Edit 2
Now with compilation! Had to do 10x more iteration:
(benchmark-run 100000
(haxe-replace-string "." "bar" "foo.buzz"))
=> (0.8736970000000001 14 0.47306700000000035)
(benchmark-run 100000
(replace-in-string "." "bar" "foo.buzz"))
=> (1.25983 29 0.9721819999999983)
(benchmark-run 100000
(replace-string-in-string "." "bar" "foo.buzz"))
=> (11.877136 86 3.1208540000000013)
haxe-replace-string is looking good
Try this:
(defun replace-in-string (what with in)
(replace-regexp-in-string (regexp-quote what) with in nil 'literal))
s.el string manipulation library has s-replace function:
(s-replace "." "bar" "foo.buzz") ;; => "foobarbuzz"
I recommend installing s.el from Emacs package manager, if you work with strings in your Elisp.
Emacs 28.1 (still in development at time of writing) provides this as standard:
** New function 'string-replace'.
This function works along the line of 'replace-regexp-in-string', but
matching on strings instead of regexps, and does not change the global
match state.
(string-replace FROMSTRING TOSTRING INSTRING)
Replace FROMSTRING with TOSTRING in INSTRING each time it occurs.
(string-replace ".*" "BAR" "foo.*bar.*baz")
⇒ "fooBARbarBARbaz"
I'd not hope for this to be faster:
(defun haxe-replace-string (string string-a string-b)
"Because there's no function in eLisp to do this."
(loop for i from 0 upto
(- (length string) (length string-a))
for c = (aref string i)
with alen = (length string-a)
with result = nil
with last = 0
do (loop for j from i below (+ i alen)
do (unless
(char-equal
(aref string-a (- j i))
(aref string j))
(return))
finally
(setq result
(cons (substring string last (- j alen)) result)
i (1- j) last j))
finally
(return
(if result
(mapconcat
#'identity
(reverse (cons (substring string last) result)) string-b)
string))))
Becasue replace-regexp-in-string is a native function, but you never know... Anyways, I wrote this some time ago for some reason, so, if you fill like comparing the performance - you are welcome to try :)
Another idea, using temporary buffer:
(defun replace-string-in-string (what with in)
(with-temp-buffer
(insert in)
(beginning-of-buffer)
(while (search-forward what nil t)
(replace-match with nil t))
(buffer-string)))
s-replace is fine if you are ready to require it, but say you want to use a replace in string feature early in the load process and don't yet have s.el loaded or don't need all of it. Well, here is the definition of s-replace from s.el. As you can see, it has no dependencies so you can use it without requiring the rest of s.el:
(defun s-replace (old new s)
"Replaces OLD with NEW in S."
(declare (pure t) (side-effect-free t))
(replace-regexp-in-string (regexp-quote old) new s t t))

Method definition as result of function call in ClojureScript

Here's a sample piece of JS for Knockout:
function AppViewModel() {
this.firstName = ko.observable('Bob');
this.lastName = ko.observable('Smith');
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
}
In case you're unfamiliar with KO, each field on AppViewModel becomes a function (i.e. ko.observable and ko.computed each return a function. Also note that fullName depends on both functions.
How can I rewrite this to ClojureScript?
One thing to try is:
(deftype AppViewModel [firstName lastName]
Object
(fullName [this] (.computed js/ko (str (firstName) " " (lastName)))))
(defn my-model [first last]
(AppViewModel.
(.observable js/ko "Bob")
(.observable js/ko "Smith")))
It doesn't work though, since fullName becomes a function that calls ko.computed. That is, it compiles to:
my_namespace.AppViewModel.prototype.fullName = function() {
return ko.computed([cljs.core.str(this.firstName.call(null)), cljs.core.str(" "), cljs.core.str(this.lastName.call(null))].join(""))
};
How can I deal with it in ClojureScript?
Again, note the dependency of fullName on this and firstName/lastName.
Try this:
(defn my-model [first last]
(let [fname (.observable js/ko first)
lname (.observable js/ko last)
full-name (.computed js/ko #(str (fname) " " (lname)))]
(js-obj "firstName" fname
"lastName" lname
"fullName" full-name)))
Riffing on #Ankur's answer, seems like you could also do the following:
(deftype AppViewModel [firstName lastName fullName])
(defn my-model [first last]
(AppViewModel.
(.observable js/ko "Bob")
(.observable js/ko "Smith")
(.computed js/ko (str (firstName) " " (lastName)))))