I have trouble while trying to wrap up a clojure function into a Java interface.
Here is the example :
(deftype ClojureDistanceMeasure [^clojure.lang.IFn f]
DistanceMeasure
(compute ^double [this ^doubles a ^doubles b] (double (f a b))))
(defn ->distance-measure
^DistanceMeasure
[^clojure.lang.IFn f]
(ClojureDistanceMeasure. f))
The compute method from DistanceMeasure (apache maths) is supposed to return. However, whatever type of type hinting I try (before args with ^, wrap into a hinted anonymous function), the progrom refuses to compile : mismatched return type, expected:double, had : java.lang.Object .
Is this a known issue ? Is there a way to override this (even with Java code) ?
I even tried silly code, did not work too
(deftype ClojureDistanceMeasure [^clojure.lang.IFn f]
DistanceMeasure
(compute [this ^doubles a ^doubles b] (let [result (f a b)] (double (+ result 0.0)))))
This is strange because it works for other similar interfaces.
Thanks
This solves the problem :
(deftype ClojureDistanceMeasure [^clojure.lang.IFn f]
DistanceMeasure
(compute ^double [this a b] (f ^doubles a ^doubles b)))
Same without inner type hints : I must remove arguments hints and it works. I do not know if it is a Clojure missing part of issue tough.
Related
I've got a function that needs to call slightly different logic depending on which keys are provided. Right now I'm using this ugly "nested-if" structure. Can someone show me a better, cleaner way to do this?
(defn myfunc
"Do different things depending on which keys are given."
[{:keys [a b c]}]
;; If (myfunc {:a})
(if (not (nil? a))
(do-a)
;; If (myfunc {:b})
(if (not (nil? b))
(do-b)
;; If (myfunc {:c})
(if (not (nil? c))
(do-c)
;; If none of the above keys are available, do d
(do-d)))))
I could use (contains? ...) but then I would have to not specify the keys in the signature, and it doesn't really improve the nested structure.
Ideally I would be able to do something like this:
(defn myfunc
"Do different things depending on which keys are given."
[{:keys [a b c]}]
(if (two-or-more-of [a b c])
(some-error)
(with
:a (do-a arg1)
:b (do-b arg2)
:c (do-c arg1 arg2)
else (do-d))))
Note: I'm not good enough with macros to write one, but I would take someone else's if that's the right answer and someone wanted to =)
There is no need to write a macro, clojure has one for you. Use cond to get rid of your nested if
(defn myfunc
[{:keys [a b c]}]
(cond (two-or-more-of [a b c]) (some-error)
(not (nil? a)) (do-a)
(not (nil? b)) (do-b)
(not (nil? c)) (do-c)
:else (do-d)))
I havent tested this, but I think it should work. You can also do it in a way closer to your original idea.
(defn myfunc
[{:keys [a b c]}]
(if (two-or-more-of [a b c])
(some-error)
(condp = (some identity [a b c])
a (do-a)
b (do-b)
c (do-c)
(do-d)))) ; default
If I run the following code in the REPL
(let [f '.startsWith] (f "abab" "a"))
it is evaluated to "a" instead of 'true'. Could someone please explain me this surprising result?
Actually, the real code, I want to make work is the following.
(defn set-up-bean! [bean functions-and-parameters]
(doseq [[f p] functions-and-parameters]
(f bean p))
(.init bean))
What I want to achieve is, to make the following two function calls do the same thing.
(set-up-bean! bean [['.setMember "a"]])
and
(do
(.setMember bean "a")
(.init bean))
One conventional approach is to use an anonymous function
(let [f (fn [a b] (.startsWith ^String a ^String b))] (f "abab" "a"))
...as this lets you type-hint parameters as-needed. You might also consider memfn:
(let [f (memfn startsWith String)] (f "abab" "a"))
In any event -- dot notation is syntactical sugar for interop, rather than providing real callable functions.
I've generated a seq of arg lists, e.g.:
[[a b c]
[d e f]
[g h i]]
... such that (map (partial apply f) that-seq) should produce a list of the same result. I want to check if all of these indeed produce that same result. Normally, you'd use the are macro for something like this, but I don't have a literal bunch of exprs to test against: I have a seq. So, I guess I want the "equivalent" of (apply are ...). As far as I can tell, my options are:
write a macro
Use every? true?, giving up on useful error messages.
Are there any better ways to do this?
Use this for more accurate reporting
(testing "blake2b defaults are accurate"
(doseq [args-variation blake2b-empty-args-variations]
(is (= (seq empty-string-digest)
(seq (blake2b args-variation)))
(str "Args variation: " (seq args-variation)))))
FYI, for now, I've gone with:
(testing "blake2b defaults are accurate"
(let [results (map #(apply blake2b %) blake2b-empty-args-variations)]
(is (every? (partial array-eq empty-string-digest) results))))
I'd like to implement some basic Physics/Chemistry formulas in Clojure.
I want to emphasize not on performance but on convenience, so the main
feature is type-checking. I was thinking that attaching meta to numbers
would accomplish the task.
For instance, this function:
(defn force [mass accel]
(* mass accel))
Should
Access the meta of first argument
Make sure it's of mass type, i.e. kilograms, grams etc. Throw an error if it's not.
Convert the numeric value to kilograms.
Do the same for acceleration.
Return the result with meta of Newtons.
I can overload * and other functions appropriately in my namespace.
The only problem is that it's impossible to attach meta to a Double.
What's a good way to get a something that behaves like a number, but can have metadata?
All this is much easier if you just create maps that contain both a number and a unit, rather than trying to smuggle the unit in as part of the number's metadata. After all, the unit is not conceptually bookkeeping data about the number: it is an integral part of the computation you are performing. And it's not as if you can ever use the number while ignoring its unit, so the ability to pass a decorated number into some "dumb" unit-unaware function such as + is not interesting either.
Given all this, it's easy to implement your force example function:
(defn force [{munit :unit :as mass} {aunit :unit :as accel}]
(assert (mass? munit))
(assert (accel? aunit))
{:unit :newton, :magnitude (* (:magnitude (to-kg mass))
(:magnitude (to-mss accel)))})
And of course if your to-kg and to-mss functions check the types themselves, you can omit them in force. Don't give up on the simplicity and transparency of maps for the imagined convenience of having numbers with metadata on them.
Here's an approach using gen-class. I just mocked the functions for checking and normalizing units. The only operation implemented is * which is used in force.
Please note that since the code is using gen-class and compile you'll need to save the following code to a file named big_decimal_meta.clj in the src folder of your leiningen project folder and then load it.
BigDecimalMeta using gen-class:
(ns big-decimal-meta
(:refer-clojure :exclude [* force])
(:gen-class
:name BigDecimalMeta
:extends java.math.BigDecimal
:state metadata
:init init
:implements [clojure.lang.IObj]))
(defn -init [& args]
[args (atom nil)])
(defn -withMeta [this metadata]
(reset! (.metadata this) metadata)
this)
(defn -meta [this]
(deref (.metadata this)))
(compile 'big-decimal-meta)
* and force functions with some example code:
(def x (with-meta (BigDecimalMeta. 1) {:unit :kg}))
(def y (with-meta (BigDecimalMeta. 3.5) {:unit :mss}))
(def z (with-meta (BigDecimalMeta. 4.5) {:unit :V}))
(defn unit [x]
(-> x meta :unit))
(defn * [x y]
(BigDecimalMeta. (str (.multiply x y))))
(defn mass? [x]
(#{:kg :gr :mg ,,,} (unit x)))
(defn accel? [x]
(#{:mss ,,,} (unit x)))
(defn to-kg [x] x)
(defn to-mss [x] x)
(defn force [mass accel]
(assert (mass? mass))
(assert (accel? accel))
(let [mass (to-kg mass)
accel (to-mss accel)]
(with-meta (* mass accel) {:unit :N})))
(println (force x y) (meta (force x y)))
(println (force x z) (meta (force x z)))
Why don't when-let and if-let support multiple bindings by default?
So:
(when-let [a ...
b ...]
(+ a b))
...instead of:
(when-let [a ...
(when-let [b ...
(+ a b)))
I am aware that I can write my own macro or use a monad (as described here: http://inclojurewetrust.blogspot.com/2010/12/when-let-maybe.html).
Because (for if-let, at least) it's not obvious what to do with the "else" cases.
At least, motivated by Better way to nest if-let in clojure I started to write a macro that did this. Given
(if-let* [a ...
b ...]
action
other)
it would generate
(if-let [a ...]
(if-let [b ...]
action
?))
and it wasn't clear to me how to continue (there are two places for "else").
You can say that there should be a single alternative for any failure, or none for when-let, but if any of the tests mutate state then things are still going to get messy.
In short, it's a little more complicated than I expected, and so I guess the current approach avoids having to make a call on what the solution should be.
Another way of saying the same thing: you're assuming if-let should nest like let. A better model might be cond, which isn't a "nested if" but more an "alternative if", and so doesn't fit well with scopes... or, yet another way of saying it: if doesn't handle this case any better.
Here is when-let*:
(defmacro when-let*
"Multiple binding version of when-let"
[bindings & body]
(if (seq bindings)
`(when-let [~(first bindings) ~(second bindings)]
(when-let* ~(vec (drop 2 bindings)) ~#body))
`(do ~#body)))
Usage:
user=> (when-let* [a 1 b 2 c 3]
(println "yeah!")
a)
;;=>yeah!
;;=>1
user=> (when-let* [a 1 b nil c 3]
(println "damn! b is nil")
a)
;;=>nil
Here is if-let*:
(defmacro if-let*
"Multiple binding version of if-let"
([bindings then]
`(if-let* ~bindings ~then nil))
([bindings then else]
(if (seq bindings)
`(if-let [~(first bindings) ~(second bindings)]
(if-let* ~(vec (drop 2 bindings)) ~then ~else)
~else)
then)))
Usage:
user=> (if-let* [a 1
b 2
c (+ a b)]
c
:some-val)
;;=> 3
user=> (if-let* [a 1 b "Damn!" c nil]
a
:some-val)
;;=> :some-val
EDIT: It turned out bindings should not be leaked in the else form.
If you use cats, then there is a mlet function that you might find useful :
(use 'cats.builtin)
(require '[cats.core :as m])
(require '[cats.monad.maybe :as maybe])
(m/mlet [x (maybe/just 42)
y nil]
(m/return (+ x y)))
;; => nil
As you can see, the mlet short-circuits when encountering a nil value.
(from section 6.5.1 nil)