Fork me on GitHub
Drew Verlee01:12:43

how would i go about making this work (= “pos?” (let [f pos?] (??? f)))

Drew Verlee01:12:19

str works if called on the original function, but not if its a … reference?

Drew Verlee01:12:45

googling around is getting me no where


What does str return when you call it on f?


I'm afk so I don't have my trusty repl


Oh wait, I keep forgetting my phone has a repl


In both cases I get "clojure.core$pos_QMARK_@30o1blahblah"


This is on clojure version 1.7 since the repl for Android hasn't bumped to the latest version


Thank you @seancorfield for the resources!


@drewverlee I forgot to mention you in my replies. Is what I got similar to what you got?

Drew Verlee02:12:24

@gdeer81 i get the same. I’m curious how i might get just the plan name. but its not that big of a deal.


The issue is that when you ask clojure for the details of something it is very precise


This might require a custom function to parse the long name into the simple name


(clojure.string/replace (first (re-seq #"pos_QMARK" (str pos?))) #"_QMARK" "?")


A naive implementation but demonstrates what I meant

Drew Verlee03:12:05

@gdeer81 gotcha. i can use the detailed name just as well.


Too late, I've already spent an hour trying to figure out the regex that will match every possible name between the $ and @ in the long name


Once I figure it out I'll create a library for it and throw it up on clojars


@gdeer81 just joined - what are you trying to figure out?


I have to calculate the lcm of several numbers.


I can calculate it for 2 numbers like this :

(defn gcd [a b]
  (if (zero? b)
    (recur b (mod a b))))

(defn lcmv
  [a b]
  (/ (* a b) (gcd a b)))  


but how can I make it work with more then 2 numbers. Please some tips and not the answer


@raspasov returning the simple name of a function as a string (let [f inc] (stringify-var-name f)) => "inc"


@gdeer81 do you ever sleep ?


i am going to try again today with clojurescript


sleep is overrated


@roelofw okay one last tip and then I'm out. See if you can use reduce


although i am only 34 and on a day-to-day basis i need at least 6 hours to sleep, that is, waking up with less is near impossible lately


@ashur a problem I know


Not sure if that tip is too vague or if I gave away the answer


you gave away the answer


I think I have a idea


reduce lcvm 0 args


@ashnur I have some days I can sleep some 14 hours a day


anyone can sleep a lot 😄


although sometimes it's hard 😞. like when you are sick or in pain. so not quite true that anyone 😞


but generally speaking i always tell people that they should learn to meditate on a basic level and they would then be able to control their sleep much better


I sometimes to medidate on my yoga lessons


This is a conversation for off-topic


yep, I will stop with this one


I'm getting an error message I can't figure out for this code:

(defn transit [we]
  (let [transform (comp
                    (map (partial choose we))
                    (mapcat (fn [me] (make (:choice me) we me))))
        reduction (fn [acc me]
                    (let [me-gen (get me :generation 0) acc-gen (get-in acc [0 :generation] 0)]
                        (= me-gen acc-gen) (conj acc me)
                        (> me-gen acc-gen) [me]
                        :else acc)))]
    (transduce transform reduction [] we)))
Exception in thread "LWJGL Application" clojure.lang.ArityException: Wrong number of args (1) passed to: core/transit/reduction--73


why would transduce call the reduction function with one argument?


transducers have a different signature than reducers


can be called with 0,1,2 args i think


sorry, its a fn thats called with one arg, which returns another fn of 0,1,2 args


always confuses me


JK "f should be a reducing step function that accepts both 1 and 2 arguments, if it accepts only 2 you can add the arity-1 with 'completing'."


How can I test this function with clojure.test :

(defn read-data-painting
  "Reads the title, description, date , collection, colors and url of a image"
  (let [art-objects (-> (str "" id )
                        (client/get {:as :json :query-params {:key (env :key) :format "json" :type "schilderij" :toppieces "True"}})
        name        (-> art-objects
        description (:description art-objects)
        date (get-in art-objects [:dating :year])
        collectie (first (:objectCollection art-objects))
        colors (:colors art-objects)]
    {:id id :name name :description description :date date :collectie collectie :colors colors}))  


I think I have to mock up the client-get part. Do I have to copy the whole file into a test function or can I do it another way?


it doesn't say in the documentation at or what the arity-1 overload on f actually does. What is it used for?


"If init is not supplied, (f) will be called to produce it"


although i dont know why in your case it would need to


@olslash (f) is zero args, not one arg


yeah, sorry, i shouldnt be trying to answer questions during a late night binge -- best i can say is give it a 1ary impl and put a print in there 🙂


Nobody to help me ?


@roelofw I think function should be decomposed. It has too many responsibilities. Something else should grab Json that you want to deconstruct. The Json should be past into your function. Then you have a separation of responsibilities. I.e. SRP. If you follow that the test should become easier

Shantanu Kumar19:12:02

@roelofw Are you trying to simulate client/get for a test condition?


@bigkahuna so seperate function that takes the id and returns the response ?

Shantanu Kumar19:12:11

I think you can get started with (with-redefs [client/get (fn [& args] mock-value)] …test-code-here...)

Shantanu Kumar19:12:39

but remember that with-redefs is only for very simple scenarios


and I can use that instead of the client/get so I copy the function and change that @kumarshantanu

Shantanu Kumar19:12:56

@roelofw Yes, with-redefs lets you temporarily mock vars


If the client/get is a REST call then it should be in its own function IMO. You can pass it into the function as well as the Id. That way you can mock it to return a stock Json output so your test can then concentrate on testing that the function destructs the json as expected.


oke, I have to think then how to do this on a right way

Shantanu Kumar19:12:11

I think ideally (as @bigkahuna suggested) you should define your fn thusly: (defn read-data-painting [http-get id] …), so that you can call http-get fn instead of client/get, and during test you can pass a mock version for http-get


Also bear in mind that when testing, you ideally want to test functions in a pure fashion so any collaborators should be externalised or to put it another way there shouldn't be any side effects. Having the REST call embedded within the function is a side effect which makes your function harder to test than it should be. You shouldn't need a real endpoint to test your function's logic. By passing in the function for REST means the function for destructuring can be tested in a pure fashion. In an OO world, this would be seen as externalising your collaborators so they can be mocked.


@seancorfield is there a way in Clojure to define my MySQL relationships in an ORM-like model? Or do I create tables and their relationships strictly in my database?


I’m wondering if there is a way when I run my application to build all of its database table dependencies?


@kyle_schmidt think about what that looks like in a functional world. If you have data and functions then what you are asking is can I build a database from a data model. This can be done and is part of the concept behind Datomic. However, not sure anyone has written anything to auto generate a relational database schema from a Clojure data structure.


@kumarshantanu I need that url call there because it depends on the id . So I think I cannot make it pure


@agile_geek It sounds like a record might be a good abstraction for a sql table?


@kyle_schmidt yeah or just a plain map


I'm sure it would be possible to generate a relational schema from a plumatic schema or Spec definition


@agile_geek Do you know a good way to test a function which is not pure because It's needs a call to a external source ?


It's not ideal but you can use with-redefs to redefine the fn that calls the external source but that's not ideal


Or you can pass the fn that calls the source as an argument to your function.


In either case in the test you can supply a dummy fn that returns the data you want for your test


Oke, so make for all api calls seperate functions and in the test make a function that return the same as the real function, @agile_geek ?


Yes. Make the api call fns arguments to the function you want to test so in the production code you pass the real api fn and in test u pass the dummy one. Also you can use multiple arity versions of production code. One arity has the api fn and one that doesn't. The one that doesn't calls the one that does passing the real api fn.


In the test you use the version with the extra api call argument


Oke, I have to think how to do that. I think I can better look for a bette way to achieve the same


The version that I made is it seems not testable at all


This is a pretty std way to mock external dependencies and is quite powerful


oke, I will think about it . At this moment I understand what you mean but do not see how to make it work in real


Thanks for the help


Ok have a think about it. Basically you are using high order functions. Passing a function as an argument to another. Good luck


@kyle_schmidt I’m the wrong person to ask about ORM-like stuff — I’ve given conference talks on why ORM is evil and I’ve ranted and raged on mailing lists about that topic too!


I would just use hash maps for the rows and avoid formal “modeling” as much as possible, to be honest. I don’t even like FK constraints: I treat the database as a dumb persistence system for the most part.


@agile_geek oke, then I have to hit some books to learn more about higher functions work in clojuer


that is a subject I did not see in the clojure koans or the first challenges of 4clojure


You've probably already seen simple examples of passing a fn to a fn


@seancorfield: interesting. So do you build your tables in your DBMS and then build an application that references the tables? Separating data from logic?


@kyle_schmidt The DBA is responsible for making sure the database schema is efficient and correct (in terms of data types). They don’t like FK constraints either so we’re in agreement there. Inside Clojure, tables are just sequences of hash maps (and rows are just hash maps). At the boundaries of the system, we read hash maps from the database and write data back to the database.


After all, our application is just a set of functions that operate on data.


Gotcha. I guess I'm speaking from the DBA and engineer perspective since I'm in charge of both. Was looking to see if I could manage this somehow in one place


I build my apps like that even without a dedicated DBA. Let relational databases do what they do best


Not sure what “duplication” you’re trying to avoid tho’ @kyle_schmidt ? Unless you want “specs” of your tables, you’re not really going to have anything in Clojure that duplicates the DB schema… and I wouldn’t consider the Clojure / DB edge to be a system boundary that needed validation, to be honest (unless you’re specifically dealing with a 3rd party system’s DB that you can’t trust — but then you didn’t control the schema for that anyway).


@agile_geek oke, so your are talking about this read_date(f ) where f is in production the client-get and in test only something like this {:id 1 :name '" Roelof"} as a example


I agree with @seancorfield. I would put Specs on the api side of my app but not the outbound database calls as you can control the data shape yourself.


@roelofw a fn that returns that map in test but yes...except your syntax for read_date is odd in that example


(read-date f) — stop using _ in Clojure names!


oke, I think I understand the idea


Then in tests you can say (read-date (constantly {:id 1 :name ”Roelof”}))


now time to experiment with it the next few days


oke, both thanks, I think I get the idea now


as I said time to experiment with it the next few days


Thanks @seancorfield struggling to type fast on phone... especially after 3 G & Ts 😉


Coming from a Python background and the SqlAlchemy module I can create Python classes which act as an abstraction and spec of SQL tables. If I change the spec of a class then it's reflected in the database without me having to login to the database itself


And call methods on these classes which are SQL queries under the hood


But I shouldnt worry about spec'ing out the tables in Clojure because it complects data and logic? I should just write functions that query those tables.


There are no classes in Clojure.


This is what I meant about ORM being evil.


In Clojure, it’s just data. If you change your DB schema, when you load a row, it just gives you data.


If you add a column to a table, that hash map has the extra key already.


If you remove a column, that hash map no longer has that key. If you change the data type of a column, the hash map just has a different value type for that key.


There is no code corresponding to the schema. In an OOP language, you have to specify code — an attribute definition — for every column.


(and you have to have a class for every table).


Gotcha, sorry for making you have to spell it out for me but I definitely see where you’re coming from now.


OOP is what creates that extra work, that duplication. ORM is a solution to a problem that simply doesn’t exist in FP.


Yeah a poor soln to Object Relational impedance mismatch


interesting! Ya that makes a lot of sense. I like that approach a lot!


With java.jdbc, you can say (jdbc/get-by-id db-spec :table-name the-key) and that’s it — it’ll get you a row of data from any table, given the PK. Nothing else is needed.


(jdbc/insert! db-spec :table-name map-of-data) will (attempt to) insert the given hash map as a row in the table. As long as you have no additional keys in the map and you aren’t missing any non-default keys, it’ll just work. The JDBC driver itself does all of the work for you.