Fork me on GitHub
#off-topic
<
2018-09-10
>
itsalitee00:09:23

I need some clojure stickers, any suggestions where to find/buy them from?

andy.fingerhut00:09:23

Looks like this is the official place: https://clojure.org/community/swag

bja04:09:27

Is there a product/service that I can sign up for that handles the backend of google/apple/amazon in-app purchases and subscriptions? I'd like something where I can basically pass a user-id and a receipt and get to know if a valid product should be given, as well as an api call to find out what a user-id is owed

bja04:09:59

if I don't care about reconciling between apple/google/amazon, I can just use the platform apis for this, but if I want the purchases to port between platforms, I didn't see any already baked service. Did I miss something?

bja04:09:11

also, the service would give me a webhook url that I could feed into play store/itunes/amazon and would manage the lifecycle of the subscription on my behalf (for things like returns/pauses/reups)

bja04:09:38

I know I've built this at a previous job, but I'd kinda like to not build this again if there is someone I can pay to care about it for me

lauritzsh14:09:08

Anyone here tried Elm and/or ReasonReact? What's your experience compared to Reagent/Rum?

fedreg15:09:01

I got quite a bit into Elm a couple of years ago, built a decent sized app with it, and loved it. Once I groked Elm I felt I was very productive with it and had 0 runtime exceptions. 🙂 Then about a year and a half ago I started doing Clojure at a new job, mainly on the backend but a bit on the UI with Reagent, and didn’t touch Elm for a while. Couple of weeks ago, when Elm .19 came out, I decided it would be a good time to revisit Elm for a small side project. It was very slow going… The changes to Elm .19 and the lack of practice with the language were partially to blame but the productivity gains that Clojure(script) bring just make everything else feel slow. I spent two days getting a small MVP up in Elm and was able to churn out the same in Reagent in just a couple of hours. So… my impressions: For a codebase of real size with several developers working in it, Elm still seems very appealing . However, for MVPs and smaller projects, Regent is blazing fast and tough to beat. Hope that helps! Have not tried Reason or PureScript

borkdude14:09:32

I’ve heard a lot of mixed stories about Elm, especially on the stability front. They tend to change the language or remove features (FRP) every year or so.

borkdude14:09:01

if I was going to try typed FP frontend, I’d choose PureScript or Reason

orestis14:09:28

I looked at Reason some time ago, when they were making a lot of breaking changes to the syntax itself. Haven’t looked again as it just failed my stability test, though the underlying tech (OCaml) is old and stable.

lauritzsh14:09:56

PureScript also looks interesting. Do you feel you get the same amount of "safety" with core.spec compared to typed languages? I have coded up the same UI now in Reagent+re-frame, Rum and Elm but I think it's too small (~600 lines of code) to really tell the major pain points of each language/library

lauritzsh14:09:38

If you do, is there any specific reason you use ClojureScript, besides maybe familiarity with Lisps

borkdude14:09:29

@mail228 right now we have a 16k lines cljs app. refactoring is sometimes painful. spec helps. having said that, I only have some experience with a large typed FP codebase (only some Scala and I went back to Clojure from that).

lauritzsh14:09:52

@borkdude are you using Rum or Reagent?

borkdude14:09:16

Spec is not enforced and not inferred. So your friends aren’t going to write them in places where you would have liked them and you have to manually place them at strategic places. But it does help a bunch if you use it well.

borkdude14:09:22

Reagent/Re-frame

lauritzsh15:09:24

I haven't tried Clojure on the backend yet, I have instead been checking Elixir out. ElixirScript seems very immature compared to everything though

borkdude15:09:53

Haven’t touched Elixir yet

lauritzsh15:09:58

Any particular nice to know reason for picking Reagent over Rum?

borkdude15:09:37

@mail228 it’s pretty much the default. it’s simple, easy to start with.

lauritzsh15:09:57

That's fair, re-frame is also a really nice library

lauritzsh15:09:22

I like your db can easily be checked with spec so it doesn't get corrupted

borkdude15:09:01

I think in Elm and PureScript the type system does that for you, right

dpsutton15:09:11

and infers for you

lauritzsh15:09:12

Yeah, pretty much

lauritzsh15:09:29

I would say spec is maybe more flexible but Elm enforces it upon you

borkdude15:09:41

Elm and PureScript have anonymous record types. This is a feature I think I’d like a lot, especially coming from Clojure. https://clojureverse.org/t/anonymous-record-types/2812?u=borkdude

john15:09:38

So, like a map that you can extend some type constraints too?

john15:09:08

A map sorta feels like an anonymous record

borkdude15:09:21

yes, a map with arbitrary data. you type only the thing that’s important for your function and ignore the rest

john15:09:16

maybe an extend-type on a map?

borkdude15:09:32

no, a statically verified input

borkdude15:09:56

in PureScript’s case these are normal javascript objects. the type system takes care of the immutability and correctness aspect

john15:09:49

Well, if we were checking types statically (like the stuff Mike Fikes is working on) then extending a type to a map might check constraints on that, I'd imagine

john15:09:02

But if we had a static analysis tool like that, then wouldn't extending a particular type to a map sorta be like an anonymous record?

john15:09:33

In cljs we also have specify

borkdude15:09:54

I’m not sure what you mean. maps already are “anonymous”

borkdude15:09:22

it’s not a property of the data structure how it gets checked by a static type system

john15:09:45

Right, I think you understand my meaning then. I'm probably just lacking some of your context, because I don't fully grok the code you dropped on clojureverse. The benefit in purescript's case in that code is that the anonymous record can bend the type of a thing in a local place, to satisfy the type checker?

borkdude15:09:04

In typed language you normally have something like data Person { name :: String, address :: Address, dogName :: String }. In Clojure this would be {:name ..., :address {...}, :dog-name ...}. In Clojure you can pass around keys and value combinations arbitrarily without giving this combination a name. In typed languages you have to always name these combinations, unless you have support for anonymous record types. Or you can stick them in a Map, but then you lose static guarantees (you don’t know at compile time which keys are surely in the map).

andy.fingerhut16:09:46

If it is anonymous, then is the idea that you need to define the required 'fields' and type checking behavior where such an anonymous record type is used?

john16:09:12

yeah, in purescript, does this "anonymous" record typing attach the type info in a way more ad-hoc than you'd otherwise be doing in purescript?

andy.fingerhut16:09:40

i.e. if field x you wanted to be the same type Int in 10 different anonymous record types, you would need to repeat the Int type in each of them?

borkdude16:09:47

I suggest going to http://try.purescript.org/ and playing with it:

f :: forall whatever. { x :: Int | whatever } -> { x :: Int | whatever }
f whatever = whatever { x = whatever.x + 1 }

main = render $ p (text (show res.x) <> text res.y)
    where 
      res = f { x: 1, y: "whatever" }

andy.fingerhut16:09:16

I ask because it seems to have some similarities with Clojure spec defining the 'types' (actually specs) of keys, but in spec the recommendation is to make the key names globally unique so that you can spec their 'type' only once, and it will always be the same no matter what other keys happen to be in the same maps together with it. That and Clojure spec checking/enforcement is run-time, not compile time.

borkdude16:09:18

no, there is no attaching to data structures. the data structure is just an ordinary JS object. it’s compile time, nothing gets added at runtime.

andy.fingerhut16:09:05

Is 'whatever' in that code snippet a name that could be replaced with anything else? Or is it a keyword / reserved word?

borkdude16:09:41

@andy.fingerhut yes, the name whatever is arbitrary and represents whatever else might be in that record

ddellacosta16:09:43

you can introduce a record type with fields that have a name and type, and then extend those with new fields with types

ddellacosta16:09:13

this is generally called row polymorphism as far as I’ve seen it discussed.

ddellacosta16:09:45

in Purescript this was arguably explicitly a reaction to how Haskell does it, which isn’t very flexible

andy.fingerhut16:09:47

Can I write f :: forall foo. { x :: Int | foo } -> { x :: Int | foo } then f foo = foo { x foo.x + 1 }, and it has the same meaning as the code you showed?

borkdude16:09:24

Haskell doesn’t have row polymorphism built in, but it can be done as a library, but this makes the compiler very slow.

ddellacosta16:09:45

yeah I don’t mean to suggest there aren’t a lot of great solutions to it in Haskell actually, it’s just not “baked-in”

andy.fingerhut16:09:08

If I can use foo in place of whatever, and represents a name, do you know why they call it "anonymous"?

ddellacosta16:09:08

@andy.fingerhut it looks like you just swapped variable names?

borkdude16:09:55

I renamed t to whatever since I found that name more appropriate in the context of Clojure 😉

john16:09:21

So, could one say that these anonymous records make a static language a little more dynamic, by allowing you to delay specification of some types until some data arrives at a given location (as seen at compile time, obviously)

borkdude16:09:42

@john no. it’s still as static as before. it’s all compile time checked

john16:09:56

I didn't mean to imply otherwise

borkdude16:09:11

it’s not delayed to runtime

john16:09:21

I didn't mean to imply that

ddellacosta16:09:26

^ maybe helpful John

borkdude16:09:39

oh sorry, I misread. then I think you understand correctly

john16:09:14

By "delay" I mean, specify type information later in the code walking sense. Instead of where a type is originally defined or instantiated (wrt the compile time view)

andy.fingerhut16:09:27

Do you know why they call them "anonymous" if they have names?

ddellacosta16:09:42

@andy.fingerhut this is probably the closest you’re going to find to an answer: https://www.athiemann.net/2017/07/02/superrecord.html

ddellacosta16:09:50

> An anonymous record is similar to a data type, but instead of defining it up front with a data declaration we can declare/use it on the fly.

john16:09:52

Ah, the wikipedia page on row polymorphism says it's a structural check.

dpsutton16:09:08

i think here the type itself has no name and is anonymous. { x: 1, y: "whatever" } The function f has to say what type it operates and it gives it a throwaway name and just says it must be a record with a parameter named x of type Int

dpsutton16:09:26

if i understand correctly

ddellacosta16:09:57

yeah, that’s my understanding @dpsutton, and consistent with how that superrecord post uses it

andy.fingerhut16:09:18

Ah, the whatever is like a named local parameter in the type definition, because it is scoped by the forall

dpsutton16:09:51

yes. i think it's naming basically a constrant. forall things that satisfy this, f is defined as ...

borkdude16:09:29

forall types, it just means, could be anything

andy.fingerhut16:09:33

The whatever in the first two lines of code don't have to be the same name, I think. I believe I took the use of whatever in those two lines of example code to mean that they had to be the same, and named the same thing.

borkdude16:09:02

@andy.fingerhut true. but that’s incidental. the type variables have no relation to argument names

borkdude16:09:50

I just called it whatever again. you can also name it foo or bar.

ddellacosta16:09:03

I don’t know purescript but I’d assume that type sig says, the function f, forall whatever (record types), takes a whatever with an Int-valued x, and returns a whatever with an Int-valued x

andy.fingerhut16:09:37

So Purescript, like Haskell, can at least in some cases infer the type of a function from its definition. The type it is inferring from the function definition here is one that says "I take any kind of map (map in the Clojure use of the term) as an argument -- well, almost any kind -- it has to have a key x with a value that has type Int".

borkdude16:09:37

right, but the whatevers must line up, so whatever fields there were in that map, also have to be returned

ddellacosta16:09:39

maybe @borkdude knows but I’m not sure if there is additionally some assumption that whatever definitely has a field named x, I would assume so however

ddellacosta16:09:58

ah yeah, sounds like you just confirmed it

ddellacosta16:09:39

yeah and the main distinction between Haskell and Purescript wrt record types is that in Haskell, they are fixed (leaving aside all the libraries that do crazy type-level stuff and whatnot to get around this)

andy.fingerhut16:09:41

And any later code you write that calls this function is statically checked to see if the arguments it passes to the function satisfy that constraint.

andy.fingerhut16:09:42

and those constraints can 'bubble up' to become constraints on the keys and types of their corresponding values of their parameters.

andy.fingerhut16:09:51

My first reaction is that if anyone makes something like this for Clojure, it would be Ambrose Bonnaire-Sergeant

andy.fingerhut16:09:59

I've never used core.typed, so don't have a good guess whether it has such a capability.

ddellacosta16:09:23

honestly not sure it makes much sense in Clojure, which is coming at this from the complete opposite angle

ddellacosta16:09:32

I don’t know much about core.typed though, maybe makes sense in that context?

andy.fingerhut16:09:33

It makes as much sense as static type checkers like core.typed added to Clojure do, yes?

john16:09:18

You can always do some structural checks (or arbitrary other checks) using :pre, if you're willing to wait for runtime checks.

borkdude16:09:32

@john that’s where spec also comes into play

ddellacosta16:09:57

ironically, it is roughly consistent with how the core team seems to conceive of map semantics though, vis-a-vis how keys in clojure.spec works

ddellacosta16:09:11

which I hate, haha…but I digress

andy.fingerhut16:09:24

I doubt core.typed has gotten as much adoption as Ambrose might have wished, but I believe he is working on other ideas that he thinks may have properties that might be more desirable to Clojure developers.

ddellacosta16:09:06

I’d love to see something that made it easy to integrate compile-time static checking into Clojure. I haven’t really given core.typed much of a test to be fair

ddellacosta16:09:20

just read about CircleCI dropping it a while back

borkdude16:09:45

maybe it’s not all that easy. I just asked in the PS channel how to do this:

f :: forall whatever. { x :: Int | whatever } -> { x :: Int, y :: Int | whatever }
f whatever = whatever { x = whatever.x + 1, y = 2 }
Reply: > I think you need to prove that whatever doesn’t include y, probably through RowCons?

borkdude16:09:53

not sure, I haven’t used PS in anger yet 🙂

ddellacosta16:09:38

yeah I don’t know PS so ¯\(ツ)

ddellacosta16:09:35

it’s interesting, but clojure.spec isn’t a type system so I’m less enthusiastic about that

john16:09:43

hmm, wouldn't a spec similar to the above anonymous record, which validates value types for keys, used with spectrum, sorta accomplish a similar thing?

borkdude16:09:13

probably it would be something like:

f :: forall whatever. 
  RowLacks "y" whatever =>
  { x :: Int | whatever } -> { x :: Int, y :: Int | whatever }
f whatever = whatever { x = whatever.x + 1, y = 2 }

ddellacosta16:09:39

@john yes if you’re talking about that particular thing in isolation

ddellacosta16:09:01

the difference between talking about it in a PS or Haskell context vs. Clojure (outside of core.typed) is the rest of the type system it fits into

ddellacosta16:09:08

and really as I said above clojure.spec/keys is basically exactly these semantics

john16:09:21

right, s/keys and s/def combined, to get your type relation

john16:09:16

That whole story is moving along. I think Ambrose is humming along towards his dissertation defense. He's been doing some exciting stuff in the CLJS codebase, I believe. And Mike Fike's work is related here as well. Somebody mentioned that static analysis thing might be portable to clojure too.

ddellacosta16:09:55

yeah, I’ll be interested in seeing how this all plays out. But I’m not sure there’ll ever be much of a future for static typing approaches in Clojure considering how much the core team has doubled-down on spec and seems…unenthusiastic about considering static typing approaches, even in terms of providing useful comparisons for those of us who are interested in both

ddellacosta16:09:04

but, we’ll see

john16:09:35

Well, I'm super excited to see more static analysis tools. As long as I'm the one imposing it on my system, where it makes sense, rather than me trying to restructure the whole world around a static checker tool. I guess there's some benefits you only get though when you do the latter.

borkdude17:09:46

joker is a lightweight linter that does gives some useful hints

ddellacosta18:09:07

just to be clear: I’m sure there’s a lot of utility and a strong future in Clojure for static analysis/linter/specs-at-compile-time kinda stuff. I was simply talking about core.typed and static type-checking though.

andy.fingerhut19:09:04

static type checking built-in to the default Clojure compiler, not as an option provided by a 3rd party, sounds very unlikely.

borkdude19:09:02

veeery unlikely

ddellacosta19:09:09

oh yeah I hope it’s obvious I’m not assuming that would ever happen or even that it’s surprising that it wouldn’t…haha

ddellacosta19:09:36

I’m more just talking about better integration with core.typed, in particular resolving some of the issues talked about in this post: https://circleci.com/blog/why-were-no-longer-using-core-typed/

ddellacosta19:09:53

granted, I haven’t been paying close attention to what Ambrose has been doing lately so I could be way off-base

ddellacosta19:09:44

although, I suspect solving some of the problems highlighted in that piece would take some coordination with the core team less so than further effort on his part, which is where my skepticism comes in