Fork me on GitHub
#beginners
<
2017-07-06
>
victora02:07:13

I'm using compojure and midje to develop a small REST application and run some test. I wanted to mock some requests, but I'm failing. Can somebody help me out with this? Tyvm

pawel.kapala11:07:49

How can I “map” vector of functions over a single value? I.e. is there a simpler way to achieve this:

(map (fn [f] (f 3)) [str (partial + 3) (partial * 5)])
;;=> ("3" 6 15)
Thanks!

a1311:07:33

(map #(% 3) [str (partial + 3) (partial * 5)])

a1311:07:05

but it's the same

pawel.kapala11:07:20

yeah, that’s pretty much the same 🙂

pawel.kapala11:07:16

I was looking for a function that would take a value to be applied for a couple of functions 😉

a1311:07:28

Do you want something like (map-? [vec-of-funcs…] value) ?

manutter5111:07:12

what about juxt?

pawel.kapala11:07:37

@manutter51 indeed it’s juxt Thanks!

jdeisenberg15:07:25

So, I'm writing code to manipulate a BufferedImage, and am thinking that a nested list comprehension would be the right tool for the job. However, it feels imperative and thus morally impure. Does this feeling ever happen to anyone else?

noisesmith15:07:51

a nested list comprehension would return a new list which wouldn’t help you at all

noisesmith15:07:04

what that data type requires is a nested procedural loop

noisesmith15:07:24

morality is for suckers

noisesmith15:07:03

OK - I don’t really mean that, what I mean is that moral / immoral is an extremely unhelpful model in software design. The right question is what are the benefits and costs of a particular programming approach, and an immutable / declarative approach is unlikely to help you make a buffered image

jdeisenberg15:07:39

A new list is what I do want. getRGB() gave me an array of integers, and I want to produce a new set of integers which I can pass to setRGB() and create a new BufferedImage.

noisesmith15:07:58

I mean, clojure has immutable associative sequential data (vectors) if you want immutable data

jdeisenberg15:07:47

Because getRGB() returns a one-dimensional array of integers, (int-array) will take my output list and make it into the array of integers that setRGB() expects.

noisesmith15:07:11

so what exactly did you have in mind that would be less imperative and therefore more admirable?

jdeisenberg15:07:42

Using map and reduce to transform the input data to the output.

noisesmith15:07:07

reduce is more imperative than a list comprehension, if we are ranking things

noisesmith15:07:01

for is lazy and declarative, reduce is eager and procedural

noisesmith15:07:34

though if the problem matches reduce, we have areduce that can be used to directly consume an array and put the result into another array https://clojuredocs.org/clojure.core/areduce

noisesmith15:07:03

especially since the size of the output and the type of every element is known beforehand

noisesmith15:07:39

or perhaps more directly, if it’s a pixel->pixel transform, amap https://clojuredocs.org/clojure.core/amap

noisesmith15:07:03

all that said, if you need to speculatively do many parallel transforms, or do more complex and generalized operation where immutability helps, sure, use for or reduce…

jdeisenberg15:07:09

Thank you; I did not know about those.

noisesmith16:07:31

@jdeisenberg though I was dismissive about concerns about code being “morally impure”, I do think I understand and agree with the underlying concern. If code is meant to be reusable with idiomatic clojure code, it should prefer immutable and declaritive code that is referentially transparent (immutable, avoids hidden state, avoids custom data types). But code that transforms one image into another is fundamentally not thing IMHO - it’s not something that could be at the core of an idiomatic clojure ecosystem, it’s an edge touching a specific data representation useful to a specific domain

noisesmith16:07:20

if you were writing a library for making images, you could consider how to design things so that clojure patterns of using plain immutable and referentially clear data and functions would be able to cleanly transform an image, but when directly interacting with the image, you not only need to get your hands dirty with a mutable array type and some wonky non-general apis, you also will benefit from not trying to impose clojure design concerns on that boundary

noisesmith16:07:07

there’s a place to think about good clojure design! - but that place isn’t the direct interaction with an existing procedural / OO api - it’s a bit further into a thing that you may not even need to build

noisesmith16:07:37

that’s way too much… TL;DR - if you want to transform one array into another, amap is super direct; if you want to make a general and pure interface to images from clojure that’s a much bigger job and you still might end up wanting something like amap in the code that directly interacts with the underlying api

swizzard16:07:54

somewhat related to the discussion about purity and edge-touching: i’m reading daniel shiffman’s The Nature of Code, and have been trying to think about how to translate it into quil

swizzard16:07:57

the problem is that if the position is out-of-bounds, then both position and velocity need to be updated

swizzard16:07:13

and ‘out-of-bounds’ can be either on the x- or y-axis

mudphone03:07:56

Hi @swizzard, I wrote that code a while back. Maybe another approach is to accumulate changes (for x and then y tests) and then swap the atom after checking if anything changed (touched an edge)

mudphone03:07:06

If you're avoiding atoms, I think that approach would work if it's wrapped in a fn and spits out the accumulated changes (changed coords)... or the same coords (for no changes)

swizzard16:07:13

but that a) uses an atom and b) won’t address cases when the x and y coordinates are oob

noisesmith16:07:47

@swizzard (let [[x y] (if (...) [....] [....])] ...) is a general pattern for when you need to update two valus

noisesmith16:07:01

just be sure to return both values from each branch of the if

swizzard16:07:25

but it’s actually 4 values, on some level

swizzard16:07:39

i was thinking about using core.match

noisesmith16:07:56

I’d just destructure the 4

noisesmith16:07:18

or reify the condition and reuse it in a series of bindings

a1316:07:20

from 2 hashmaps

noisesmith16:07:32

that’s a decent option, yes

swizzard16:07:58

again, the thing is that there are two separate conditions

swizzard16:07:03

that both have to be checked

a1316:07:12

chain them

noisesmith16:07:13

sure, let lets you do multiple bindings

a1316:07:36

smth like

(-> [position velocity]
      check-and-update-1
      check-and-update-2)

swizzard16:07:23

(defn check-bounds [^PVector loc ^PVector vel]
  (let [lx (.x loc) ly (.y loc)
        vx (.x vel) vy (.y vel)]
    (when (> lx (q/width))
      (do (.set loc q/width ly)
          (.set vel (* vx -1) vy)))
    (when (< lx 0)
      (do (.set loc 0 ly)
          (.set vel (* vx -1) vy)))
    (when (> ly (q/height))
      (do (.set loc lx (q/height))
          (.set vel vx (* vy -1))))
    (when (< ly 0)
      (do (.set loc lx 0)
          (.set vel vx (* vy -1))))))

swizzard16:07:08

i feel like rich hickey is going to have me arrested

a1316:07:14

it's imperative as hell!

swizzard16:07:33

it’s gross and i hate it?

a1316:07:54

my eyes are bleeding

swizzard16:07:55

i really want to believe there’s a better move here, i’m just not smart/experienced enough to figure it out

noisesmith16:07:33

(cond-> [loc vel] (x-wrap? loc vel) (do-x-wrap) (x-under? loc vel) (do-x-reverse-wrap))

noisesmith16:07:53

where do-x-wrap and do-x-reverse-wrap return a new loc and vel

a1316:07:03

or smth like

(defn check1 [[pos vel]]
  (let [px (:x pos)
        vx (:x vel)
        npx (if (> px width)
              width
              (max 0 px))
        nvx (if (or (> px width)
                    (< px 0))
              (- vx)
              vx)]
    [(assoc pos :x npx)
     (assoc vel :x npx)]))

(defn check2 [[pos vel]]
  (let [py (:y pos)
        vy (:y vel)
        npy (min py height)
        nvy (if (> py height)
              (- vy)
              vy)]
    [(assoc pos :y npy)
     (assoc vel :y nvy)]))
              
(->  [position velocity]
     check1
     check2)

noisesmith16:07:46

right - it’s the same pattern, each function takes both position and velocity and returns them both

swizzard16:07:24

i didn’t know about cond->

noisesmith16:07:45

the only annoying thing about cond-> is that the checks can’t use data created mid stream

noisesmith16:07:55

the checks have to use data that’s visible outside the cond-> block

swizzard16:07:04

that seems a small price to pay

noisesmith16:07:09

but if you can make that work, cond-> is great

noisesmith16:07:05

sometimes that means that instead of one (cond-> …) you have (-> x (cond-> ….) (as-> … (cond-> ….)))

noisesmith16:07:27

where as-> is the thing that saves your ass by letting you bind things mid stream

noisesmith16:07:17

but there’s always plain old let blocks too - remember that a let value expression can refer to bindings before it in the block

billbarnhill22:07:04

Good evening all. I'm looking at Clojure templating libraries. While I like hiccup, I prefer creating my HTML templates separately and getting them looking just right, so I was looking at Selmer, Enlive, Laser, or Fleet. Unfortunately all the ones I looked at have no commit more recent than 2 years ago. What templating libraries are current, or is pretty much everyone just using hiccup?

mudphone03:07:53

Another option is kioo, if you want to ingest html (with Reagent).

mudphone03:07:09

My personal favorite is Hoplon :)

ballpointcarrot23:07:54

not crazy busy, but not devoid of commits, either.

billbarnhill23:07:31

Thanks. I must have been looking at a clone

billbarnhill23:07:21

Is it in wide use, or do most just use Hiccup?

ballpointcarrot23:07:46

I can’t speak for the community as a whole - my last project was via Hiccup through.

ballpointcarrot23:07:12

that said, there’s nothing stopping you from doing an API on the backend, and a client-side SPA in the front, either.

ballpointcarrot23:07:21

https://clojars.org/selmer vs https://clojars.org/hiccup downloads show about a 1:10 ratio between the two projects

billbarnhill23:07:53

Interesting, thanks. I wonder if that disparity is due to hiccup being used for people learning clojure with web experiment. Hiccup seems great for small projects, or experimenting with clojure. My problem may be my newness to Clojure too

billbarnhill23:07:25

I imagine if I want my next job to be as a Clojure dev I need to learn to be functional (pun) with both Selmer and Hiccup, so I'll look at both of them.