This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-04-19
Channels
- # aws-lambda (4)
- # beginners (62)
- # cider (20)
- # cljs-dev (9)
- # cljsrn (13)
- # clojars (3)
- # clojure (105)
- # clojure-brasil (1)
- # clojure-denver (1)
- # clojure-finland (4)
- # clojure-italy (23)
- # clojure-norway (1)
- # clojure-spec (6)
- # clojure-uk (56)
- # clojurescript (41)
- # cursive (10)
- # datomic (25)
- # emacs (23)
- # figwheel (2)
- # fulcro (133)
- # graphql (12)
- # hoplon (32)
- # instaparse (13)
- # keechma (1)
- # lein-figwheel (1)
- # luminus (1)
- # lumo (1)
- # nyc (2)
- # off-topic (34)
- # om (2)
- # onyx (10)
- # pedestal (8)
- # portkey (1)
- # re-frame (10)
- # reagent (26)
- # ring (8)
- # shadow-cljs (77)
- # spacemacs (4)
- # sql (8)
- # tools-deps (15)
- # vim (9)
aren't there issues with having everything in the same folder when pulling macros into clojurescript?
unfortunately, I have macros that are going to be used in clj and cljs, and I recall having issues in the past
The placement of files in folders won't hurt or help anything. (Source files are simply "on the classpath", and it doesn't really matter where they are.)
I was going to have two differing classpaths between clj and cljs, where clj --> {src/clj, src/cljc] and cljs --> [src/cljs src/cljc]
ya, I prefer that as well. I suppose I would just be fighting with the extension types instead
if you have foo.clj, foo.cljs, and foo.cljc, each with the same functions, which takes precedence in clojure and clojurescript when requiring?
I can't think of any reason to create all 3 of those files for the same namespace, since then the .cljc file would never be loaded.
> When finding a library in any Clojure dialect, the platform-specific resource will be found and loaded first (.clj or .cljs) before the portable file (.cljc) is found or loaded. This allows the opportunity to override a platform-agnostic file with a platform-specific implementation of a namespace. from https://dev.clojure.org/display/design/Reader+Conditionals
If you ever forget the details of the rule, just (require 'bogus)
and the error message will tell you the order tried.
^ Oh, I guess https://dev.clojure.org/jira/browse/CLJ-1797 hasn't yet been applied
Is there a macro to make is better to write:
(let [x ...]
(try
(let [y ...]
(try
(let [z ...]
(f x y z))
(catch (release z))
(catch (release y)))
(catch (release x)))
this is almost like with-open, but I need to specify my own dtor function instead of just using .closeI am not aware of one, but it doesn't appear like it would be a difficult macro to write.
there is a long outstanding request to make with-open work with a Closeable protocol
How to rewrite that code to make It work?
(defn setupe-function
([db [slides sw-mod]] (assoc db :focus-slide 0
:sw-mod sw-mod
:slides-count (count slides)))
([db [slides sw-mod width]] (assoc db :focus-slide 0
:sw-mod sw-mod
:slides-count (count slides))))
I did it so:
(fn [db [slides sw-mod & args]]
(let [width (first args)]
(-> (assoc db :focus-slide 0
:sw-mod sw-mod
:slides-count (count slides))
(#(if (nil? width)
%
(assoc % :main-wrapper-width width))))))
but may be somebody know a more recommended way?@al.vyguzov You can simplify that with cond->
(cond-> (assoc db ...)
width (assoc :main-wrapper-width width)
But depending on how you're using that hash map, just assoc
ing in :main-wrapper-width
regardless is probably going to work. After all (:a {:a nil})
and (:a {})
are both nil
.
@al.vyguzov You can also destructure in the argument list to avoid the let
:
(fn [db [slides sw-mod & [width]]]
@seancorfield I didn`t understand your second message completely, but your suggested code looks great
(defn setup-function
[db [slides sw-mod & [width]]]
(assoc db :focus-slide 0
:sw-mod sw-mod
:slides-count (count slides)
:main-wrapper-width width))
that will almost certainly do what you need.(depending on how you use :main-wrapper-width
elsewhere in your code -- but idiomatic Clojure would nil
-pun on it)
Ok, @seancorfield! Thank you
Pressing c-h in Company completions says no docs are available, while using cider-doc works. Any ideas why?
I think so. Expanding a defn just results in def-ing an fn form.
Hi all, I don't know much about the theory, but was wondering why hot reload is so easy in clojure (e.g. with lein repl) and difficult in most other mainstream languages? Besides lisps I haven't seen any that support the same kind of easy hot loading out of the box
@squarenegative It’s mostly because the language is set up to be reloadable. Clojure has a var indirection for every function or top level variable definition which you can mutate, so you can redefine just one function while keeping the rest of your environment the same and carry on
following up on that - there's indirection when the function name is in the code, but for a long running function that took another function as an argument (eg. you passed a handler function to an http server process startup) you can get the benefits of var indirection by hand - by passing #'handler instead of handler
but otherwise you don't get the reloading (without restarting the process that took that arg)
right, and there’s also direct linking which takes away the indirection at compile time
direct linking replaces var calls being compiled with direct calls
the var path however still exists and NEW code can still invoke via the vars
for example, the Clojure core namespaces are direct linked so calls from say clojure.set into clojure.core are compiled and direct linked. But if your own code makes calls into clojure.core, those calls are not direct linked (unless you compile your code with direct linking on)
given the following function:
(defn my-inc [x]
(let [inner-inc (fn [] (inc x))]
(inner-inc x)))
Is it true that the inner-inc
function is compiled once and attached to the Java class for the namespace, and a new fn
isn’t “created” for every invocation of my-inc
? Or, to the root of the question, is there any difference (in object allocation) between this example and the case where inner-inc
is defined via defn
?
I thought I came across that in a conversation once, but I can’t find the answer in the codebase.the exact nature of how it is compiled and the exact set of classes and how they interact sort of depends, there is not always a class for a namespace only when you aot compile, but yes each fn, def'ed or not is compiled to a single class, of which an instance is created as needed
you can imagine the compiler turning the above in to something like
(deftype SomeFnType [x]
clojure.lang.IFn
(invoke [_] (inc x)))
(def m-inc [x]
(let [inner-inc (SomeFnType. x)]
(inner-inc x)))
@arrdem what are you trying to accomplish? Often times, just pushing data between nodes is good enough, if you can get the right functionality deployed a priori
Is anyone familiar with @dnolen's defunct delimited continuations library: https://github.com/swannodette/delimc ? I like his approach using atoms to store continuations, but it's hard to reconcile with Scheme examples that often don't have a reset
outside of every shift
. For a really simple example, I'm trying to implement call/cc using this library and an implementation cwcc
from R4RS Scheme (https://github.com/tonyg/kali-scheme/blob/master/scheme/misc/shift-reset.scm) and use it to run the yin-yang puzzle: https://gist.github.com/Sophia-Gold/435b984be3a2e4509deea6956fd04242
I am pretty sure shift/reset is strictly less powerful than call-with-cc, so you can't implement call-with-cc using shift/reset
@hiredman you definitely can, but I'm not certain it's possible with this implementation
the scheme code you linked to seems to be going the other way, implementing shift/reset on top of cc
In fact, I think that statement is exactly the other way around: you can always implement undelimited continuations with delimited ones. My guess is this library prohibits that because you'd likely end up just clashing with the JVM/OS/REPL (hence why "`call/cc` considered harmful").
right, so that is call/cc in the context of some outer reset, so it is still a delimited continuation
Yeah, the outer reset part is what I suspect to be incompatible with David's implementation.
because clojure doesn't have a native call-with-cc, you have to do code transformations to get any kind of call-with-cc, and generally that is done with macros, and macros are limited to operating on their literal arguments
they can't descend in to functions called and recompile them in to some cps style to make call-with-cc possible
this is very similar to what core.async's go macro does, it effectively captures the current continuation and attaches it as a callback to a channel
but because it is a macro, and can't do whole program transformation, it is limited in scope
I understand how CPS transforms work. core.async actually uses SSA form for go
, though, although they're equivalent per Andrew Appel. Anyway, that doesn't preclude implementing cwcc
.
I've been playing around lately with using the continuation monad as an alternative to having to do the kind of program transformations that core.async does, and it seems to work well
(work well in terms of working, being flexible, and avoiding having write a compiler in a macro, the performance is likely terrible)
Do you mean the one from algo.monad
? Tbh I wasn't too impressed with that implementation from what I remember (also working in Haskell professionally, I don't see much purpose for monads in a dynamically typed language) but perhaps I should revisit it in this context. One thing I remember explicitly is it not using atoms, which is how I was doing ad hoc CPS in a Clojure project at the time.
no, I have my own implementation (I use the monad to also pass around a bundle of nio selector stuff too), I haven't looked at what is in algo.monad
Oh, cool. I've actually already implemented everything in that snippet I posted using cps; that was really easy.
The other person who contributed to David's delimc library wrote a CPS transform macro for Clojure around that time using tools.analyzer
, but it's even messier than the parse-to-state-machine
stuff from core.async. I may try dropping him a line to ask about the version with atom
s.
the cwcc in your clojure likely doesn't work because you took the scheme definition and wrapped it in a call to reset, where the assumption on the scheme side is that you wrap the code in which you call cwcc with the reset
There's a Reddit thread on cwcc
(only pertaining to Scheme) and it mentions exactly what you're saying now plus references the exact behavior I see from the first broken version I shared.
"There is no implied reset here. The implied reset is around the entire program (in a REPL there is often another one around the current evaluation)."
https://www.reddit.com/r/scheme/comments/5drp2i/is_it_possible_to_return_to_a_continuation_a_la/
clojure's calling convention is jvm method calls, and jvm method calls don't provide for continuations, so the only way to get them is to change the calling convention (continuation monad) or program analysis and transformation (delimc, the go macro, the cps compiler thing someone wrote)
https://github.com/positronic-solutions/pulley.cps/blob/master/src/com/positronic_solutions/pulley/cps.clj might be interesting, similar but more re-usable than core.async's machinery
Cool, thank you. It's nice to see an actual documented production-ready CPS transform. defmacro
s do definitely have a legibility problem when they reach this level of complexity so there's just a limit to the extent I want to decipher them when it would take less time to just rewrite them myself. The Racket folks definitely do have a one-up on that.
I may just table the serialization idea and use this library for a blog post I've been meaning to write. It makes what I wanted to demonstrate almost trivial code-wise.
You said that about this same thing I'm mentioning now a week later without having done 😛
I did write one blog post about Clojure once: https://hackernoon.com/nested-maps-considered-harmful-143add482247