No implementation of method for class: clojure.lang.ArraySeq - clojure

I wrote a Clojure function that uses recur to process through a list and returns the results back in a vector...
(defn do_stuff [input, results]
;; using recur and conj here to build up results
)
I have a another function where I need to pass the result of do_stuff, and I get this error:
No implementation of method: :to_my_format of protocol: #'com.beebunny.to_my_format found for class: clojure.lang.ArraySeq
My to_my_format function has an implementation for clojure.lang.IPersistentVector and IPersistentList. Is there a way I can convert to one or the other?
Thanks.

An easy fix is to wrap the ArraySeq with into.
(into [] array-seq)
But it might be better if you refactor the protocol to work with ISeq if all you need is to sequentially scan through the data and produce result. As such, anything that is sequential can be passed in with a simple seq call.

Related

Clojure: overriding one function in a library

This question is off the back of a previous question I asked here a few days ago. One of the comments was that I should dispense with the Ring middleware for extracting query parameters and write my own. One alternative that I thought I'd play with was harnessing the existing one to get what I want and I've been doing some digging into the Ring source code. It does almost exactly what I want. If I write out how I understand it works:
A middleware has the function wrap-params which calls params-request
params-request adds a params map to the request map, calls assoc-query-params
assoc-query-params eventually calls ring.util.codec/form-decode on the incoming query string to turn it into a map
form-decode uses assoc-conj to merge values into an existing map via reduce
assoc-conj's docstring says
Associate a key with a value in a map. If the key already exists in
the map, a vector of values is associated with the key.
This last function is the one that is problematic in my previous question (TL;DR: I want the map's values to be consistent in class of either a string or a vector). With my object orientated hat on I would have easily solved this by subclassing and overriding the method that I need the behaviour changed. However for Clojure I cannot see how to just replace the one function without having to alter everything up the stack. Is this possible and is it easy, or should I be doing this another way? If it comes to it I could copy the entire middleware library and the codec one, but it seems a bit heavyweight to me.
While a custom middleware is probably the clearest way to go for this problem, don't forget that you can always override any function using with-redefs. For example:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(dotest
(with-redefs [clojure.core/range (constantly "Bogus!")]
(is= "Bogus!" (range 9))))
While this is primarily used during unit tests, it is a wide-open escape hatch that can be used to override any function.
To Clojure, there is no difference between a Var in your source code versus one in a library (or even clojure.core itself, as the example shows).
I disagree with the advice to not use Ring's param middleware. It gives you perfect information about the incoming parameters, so you if you don't like the default behavior of string-or-list, you can change the parameters however you want.
There are numerous ways to do this, but one obvious approach would be to write your own middleware, and insert it in between Ring's param middleware and your handlers.
(defn wrap-take-last-param []
(fn [handler]
(fn [req]
(handler
(update req :params
(fn [params]
(into {}
(for [[k v] params]
[k (if (string? v) v, (last v)]))))))))
You could write something fancier, like adding some arguments to the function to let you specify which parameters you want to receive only the last specified, and which you would like to always receive as a list. In that case you might not want to wrap it around your entire handler, but around each of your routes separately to specify their expected parameters.

clojure cannot apply function via map to list

I seem to have a difficulty understanding how I should use clojure map. I have a list of objects called in-grids where I wan't to use method getCoordinateSystem. I guess it is important that objects in the list are of some Java class. When I directly define function in clojure then map works.
This works:
(.getCoordinateSystem (first in-grids))
but not this
(map .getCoordinateSystem in-grids)
And the error is: java.lang.RuntimeException: Unable to resolve symbol: .getCoordinateSystem in this context
I'm probably missing something really obvious here, but what exactly?
If you have an expression of the form
(map f sequence)
then f should refer to an instance of IFn which is then invoked for every element of sequence.
. is a special form, and .getCoordinateSystem does not refer to an IFn instance.
(.getCoordinateSystem (first in-grids))
is equivalent to
(. (first in-grids) (getCoordinateSystem))
You can construct a function value directly e.g.
(map #(.getCoordinateSystem %) in-grids)
Another choice which is often a handy alternative to map is the for function:
(for [grid in-grids]
(.getCoordinateSystem grid))
Using for in this manner has the same effect as map but is a bit more explicit in the "one-item-at-a-time" nature of the processing. Also, since you are calling the Java function getCoordinateSystem directly you don't need to wrap it inside a Clojure function literal.
As an alternative to Lee's answer, there's the memfn macro, which expands to code similar to that answer.
(map (memfn getCoordinateSystem) in-grids)
(macroexpand '(memfn getCoordinateSystem))
;=> (fn* ([target56622] (. target56622 (getCoordinateSystem))))

calling a library function of arbitrary name

say there's a library l, which has two functions (a and b).
Calling both functions and merging the results into a vector could be done like this:
(concat (l/a) (l/b))
Is there a way to make this more generic? I tried something like this, but it threw an exception:
(apply concat (map #(l/%) ['a 'b]))
of course, this would work:
(apply concat [l/a l/b])
Calling both functions and merging the results into a vector could be done like this:
(concat (l/a) (l/b))
No, you will not get a vector. And you will only get a sequence if those functions return sequences. Otherwise, definitely not, you will get a runtime exception with this code and your assumption.
It sounds like you have a bunch of functions and you want to concatenate the results of them all together? There is no need to quote them, just make a sequence of the functions:
[l/a l/b l/c ...]
And use apply with concat as you already are, or use reduce to accumulate values.
Call vec on the result if you need it to be a vector rather than a sequence.
Your other solutions are definitely making your code much much more complex, unnecessary, and difficult to read. (also, you almost never need to quote vars as you are doing)
It looks like you want a general way of invoking a function inside a namespace. You can construct a symbol and dereference it to find the functions, then combine the results using mapcat e.g.
(mapcat #((find-var (symbol "l" %))) ["a" "b"])
alternatively you could first find the namespace and use ns-resolve to find the vars e.g.
(let [ns (find-ns 'l)]
(mapcat #((ns-resolve ns %)) ['a 'b]))

Clojure: function composition at runtime

Problem:
Suppose I have a set of functions f_1 ... f_n that I want to compose at runtime, such that I get for example:
(f_a (f_b (f_c) (f_d)) (f_e))
Therefore I need the types of the parameters and the return value of each function in order to know, which functions I can plug into each other.
First Attempt: Annotate each function
(defn foo [n f]
^{:params [Number clojure.lang.Fn]
:return String}
(do stuff with f and n, return a string))
I don't like this approach because of obvious reasons, such as if I wanted to use clojure.core as the set of functions I would have to annotate every function, which wouldn't be very desirable.
Questions
How would you attempt to solve this problem?
Could core.typed help me with that?
I do similar things when composing the search query to pass to solr and use a map for the arguments to all the functions and have them all return a map with whatever changes the function decided to make contained in the map, and everything else returned unchanged. So in short i would:
use a map for the input and output of every function
core.typed is not helpful because everything is a map
prismatic.schema is very helpful because you can use it to know what keys are required and to write tests that validate the structure of these maps.
Projects/people with more of an inclination to statically typed functional languages will likely turn to monads in cases like this because they are a powerful tool for describing composition in a type safe way.

How do I get core clojure functions to work with my defrecords

I have a defrecord called a bag. It behaves like a list of item to count. This is sometimes called a frequency or a census. I want to be able to do the following
(def b (bag/create [:k 1 :k2 3])
(keys bag)
=> (:k :k1)
I tried the following:
(defrecord MapBag [state]
Bag
(put-n [self item n]
(let [new-n (+ n (count self item))]
(MapBag. (assoc state item new-n))))
;... some stuff
java.util.Map
(getKeys [self] (keys state)) ;TODO TEST
Object
(toString [self]
(str ("Bag: " (:state self)))))
When I try to require it in a repl I get:
java.lang.ClassFormatError: Duplicate interface name in class file compile__stub/techne/bag/MapBag (bag.clj:12)
What is going on? How do I get a keys function on my bag? Also am I going about this the correct way by assuming clojure's keys function eventually calls getKeys on the map that is its argument?
Defrecord automatically makes sure that any record it defines participates in the ipersistentmap interface. So you can call keys on it without doing anything.
So you can define a record, and instantiate and call keys like this:
user> (defrecord rec [k1 k2])
user.rec
user> (def a-rec (rec. 1 2))
#'user/a-rec
user> (keys a-rec)
(:k1 :k2)
Your error message indicates that one of your declarations is duplicating an interface that defrecord gives you for free. I think it might actually be both.
Is there some reason why you cant just use a plain vanilla map for your purposes? With clojure, you often want to use plain vanilla data structures when you can.
Edit: if for whatever reason you don't want the ipersistentmap included, look into deftype.
Rob's answer is of course correct; I'm posting this one in response to the OP's comment on it -- perhaps it might be helpful in implementing the required functionality with deftype.
I have once written an implementation of a "default map" for Clojure, which acts just like a regular map except it returns a fixed default value when asked about a key not present inside it. The code is in this Gist.
I'm not sure if it will suit your use case directly, although you can use it to do things like
user> (:earth (assoc (DefaultMap. 0 {}) :earth 8000000000))
8000000000
user> (:mars (assoc (DefaultMap. 0 {}) :earth 8000000000))
0
More importantly, it should give you an idea of what's involved in writing this sort of thing with deftype.
Then again, it's based on clojure.core/emit-defrecord, so you might look at that part of Clojure's sources instead... It's doing a lot of things which you won't have to (because it's a function for preparing macro expansions -- there's lots of syntax-quoting and the like inside it which you have to strip away from it to use the code directly), but it is certainly the highest quality source of information possible. Here's a direct link to that point in the source for the 1.2.0 release of Clojure.
Update:
One more thing I realised might be important. If you rely on a special map-like type for implementing this sort of thing, the client might merge it into a regular map and lose the "defaulting" functionality (and indeed any other special functionality) in the process. As long as the "map-likeness" illusion maintained by your type is complete enough for it to be used as a regular map, passed to Clojure's standard function etc., I think there might not be a way around that.
So, at some level the client will probably have to know that there's some "magic" involved; if they get correct answers to queries like (:mars {...}) (with no :mars in the {...}), they'll have to remember not to merge this into a regular map (merge-ing the other way around would work fine).