These are chat archives for ramda/ramda

22nd
Mar 2017
Dylan Falconer
@Falconerd
Mar 22 2017 01:00
Hey guys, I’m trying to wrap my head around this library and functional programming in general and am wondering if someone can explain why to use the first example over the 2nd?
const sortByCreatedAt = R.sortBy(R.prop('createdAt'));

const sortByProperty = R.curry((property) => R.sortBy(R.prop(property)));
James Forbes
@JAForbes
Mar 22 2017 01:09

@Falconerd hey, so a few things.

All ramda functions are automatically curried, so doing it manually is rarely necessary.

Secondly, currying a function with only 1 argument (a unary function) doesn't do anything of use, except if you want to be able to call it with no args without the function being called.

Dylan Falconer
@Falconerd
Mar 22 2017 01:11
Right, thanks. I’m still wondering if you would recommend creating a function which takes a property argument in this example, instead of creating a bunch of sortByX
All the examples I have read so far are oddly specific
James Forbes
@JAForbes
Mar 22 2017 01:12
Oh, well, its so easy to write it inline, I'd just write it inline.
Dylan Falconer
@Falconerd
Mar 22 2017 01:12
R.sortBy(R.prop(‘someProperty’)) ?
James Forbes
@JAForbes
Mar 22 2017 01:13

I mean, I wouldn't even give sortByCreatedAt a name, the definition already reads as that, and I get more guarantees reading the definition than the name.

There's exceptions, but in those cases, they are probably highly specific anyway.

@Falconerd yep
I think its also a lot nicer on the eyes with out the R.
sortBy( prop('someProperty') )
At that point naming it: sortBySomeProperty doesn't give us much
Dylan Falconer
@Falconerd
Mar 22 2017 01:14
And then import { sortBy, prop } from ‘ramda’?
This message was deleted
James Forbes
@JAForbes
Mar 22 2017 01:14
yep if your using es6 modules
Dylan Falconer
@Falconerd
Mar 22 2017 01:14
alright, that makes sense
thanks for helping clear that up, @JAForbes
James Forbes
@JAForbes
Mar 22 2017 01:15
@Falconerd my pleasure
let us know if you have any more questions :)
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:11
@JAForbes Did you happen to see my crazy thing from earlier?
James Forbes
@JAForbes
Mar 22 2017 03:16
@m59peacemaker no I didn't, very nice
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:16
oh hey!
I was trying to think of a way to pose a question
You know a decent bit about static-land, right?
James Forbes
@JAForbes
Mar 22 2017 03:21
ahhh I suppose yeah
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:22
I was thinking of taking that logic there and maybe trying to make my own types that just sort of, magic it up
James Forbes
@JAForbes
Mar 22 2017 03:22
I feel uncomfortable saying I know a decent amount about anything in this room :D
ah yeah cool idea
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:22
I'm going to have to say some dumb stuff here.... sorry about this
MyThing.of({k, v, idx}).concat(MyArrayThing.of({k, v, idx})
is it a cool idea for real?
Like, there is some merit in the world to doing something at all like that?
James Forbes
@JAForbes
Mar 22 2017 03:23
yeah there's merit, try it out
if you can turn custom interfaces/algorithms into standard interfaces/algorithms its great!
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:24
All that is happening in my brain is "I have two different functors that take this object and they know how to act on one another to inevitably produce that result I need"
James Forbes
@JAForbes
Mar 22 2017 03:24
but if it doesn't work, be happy with what you have too, cause its cool
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:26
Can you give me a starting place? static-land docs don't really help.
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:31
I did this earlier
James Forbes
@JAForbes
Mar 22 2017 03:31

I guess, the first thing we want to do is unify the structure, so there is only 1 structure.

If that's possible, they you can define some lawful functions for merging each structure via concat

If that's not possible, you might want to define all the possible structures, as a union and call that our type.

Then you can say, this type can have these forms, and your concat should be able to take any 2 forms and spit out a form that fits within your union.

static land docs are kind of an extension of fantasy land docs, so you basically want to follow the fantasy land docs, but instead of having e.g. a concat method, you'd have a concat function.
You have absolute control over the data structures you operate on, but the key thing is to ensure your types are consistent and lawful.

Johnny Hauser
@m59peacemaker
Mar 22 2017 03:31
var MyType = {
  of: value => ({
    map: fn => MyType.of(fn(value)),
    toString: () => `MyType(${value})`
  })
}
map(R.inc, MyType.of(123))
James Forbes
@JAForbes
Mar 22 2017 03:31
nice
so that's like an identity functor (I think :D)
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:32
That was just kinda guessing at what a functor should do
James Forbes
@JAForbes
Mar 22 2017 03:32
yeah nice
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:32
for real?
James Forbes
@JAForbes
Mar 22 2017 03:32
for real referring to...
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:32
So of is supposed to return an object like that?
James Forbes
@JAForbes
Mar 22 2017 03:32
ohhh
in static land yeah let's think
of kind of doesn't exist in static land
we're never instantiating anything
we're operating on existing structures that can be completely ignorant of our static land functions
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:33
ohhhh
James Forbes
@JAForbes
Mar 22 2017 03:33
but that's kind of like a fantasy land identity functor
E.g. let's say we had a maybe
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:34
Static is better?
James Forbes
@JAForbes
Mar 22 2017 03:34
in static land we could just represent it as a struct { value, isJust }
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:35
So, I have the right idea, but the value is never wrapped
well
James Forbes
@JAForbes
Mar 22 2017 03:35
Then we'd write functions like
function map( f, m ){
  return m.isJust
    ? { value: f(m.value), isJust:true  }
    : m
}
yeah we should just accept our data, and assume its well formed
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:36
yeah
Neat, that makes a ton more sense
James Forbes
@JAForbes
Mar 22 2017 03:36
if one is better / worse is really context
yeah its super neat :D
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:36
Do you realize, the docs totally do not communicate that fact
The doc author / community must take for granted that they know what it's about
James Forbes
@JAForbes
Mar 22 2017 03:36
I think a lot of stuff in this community relies on assumed knowledge, that's something I'd like to help change but I don't have a lot of time right now :(
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:37
I even thought maybe that was the case and I was like "no, if that's how it worked, it would say so" lol
James Forbes
@JAForbes
Mar 22 2017 03:37
like its not hard at all, but its just the way its written expects you to know terms, or the existence of other concepts
which works in say an academic setting because a course or text is linear
but on the internet, its not
so there is no golden path to walk down
mostly adequate is pretty good in that respect
but I think library readme's could do better
and I think we should use those terms
we just shouldn't assume they know them
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:38
when I saw the function signatures, I would have naturally thought that the data is external, since they take the value rather than having some internal access to it
James Forbes
@JAForbes
Mar 22 2017 03:38
@m59peacemaker well that's correct
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:38
but the fact that this wasn't stated somewhere made me think that it was crazy magic going on that my small mind couldn't fathom
James Forbes
@JAForbes
Mar 22 2017 03:38
yeah
which is so often the case
its like this massive wall that doesn't really exist but inhibits people
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:39
which makes me sad since I now realize function (a, b) { } was intimidating to me today hahaha
James Forbes
@JAForbes
Mar 22 2017 03:40
yeah I know what you mean
summary tags in readme's could be really good
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:41
You said "unify the structure" - that means that all the data looks the same, right?
James Forbes
@JAForbes
Mar 22 2017 03:41
hyperlinks are a bad idea I think, because the beginner doesn't know what to look for on the page you link them to, and that page has links, and so on
hyperlinks in a summary is great though
well...
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:42
or, basically the same things can be said of it
it's the of the same nature?
James Forbes
@JAForbes
Mar 22 2017 03:42

its not that the structure has to be the same, it just makes everything easier.

And how do you know you're being lawful unless you define what a valid form of your type is

like if map is M a -> M a, I need to know what a looks like
that said
let's say we define Map differently
let's say we operate on raw values and treat nulls as Nothing
function map(f, m){
  return m != null
    ? f(m)
    : m
}
So this is broken in a way, because functors have to be able to contain any value (in or to satisfy of for example), but in static land we don't have of
so its kind of fine
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:45
My items are these
{key, value, anOptionForHowToDealWithDuplicateKeys: boolean}
James Forbes
@JAForbes
Mar 22 2017 03:46
we could use it like map( inc, 1) //=> 2 and map( inc, null) //=> null
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:46
that option is what makes everything so hard
James Forbes
@JAForbes
Mar 22 2017 03:46
but at the very least our type is a known domain
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:46
yep, your map makes perfect sense
James Forbes
@JAForbes
Mar 22 2017 03:46
I think if you just ensure meta is always there and fully populated you're set.
then you can have a separate function that fills in empty properties if you want for convenience
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:47
I can do that no problem. So it's just one type?
James Forbes
@JAForbes
Mar 22 2017 03:47
But you don't have to do (in static land) is my point I guess
@m59peacemaker I think that's always the better play
but I only point it because its cool to think "if I don't need to make the type uniform, I can write static land compliant libraries for any library!"
that's really cool
like maybe javascript arrays have some warts, but we can make them lawful via static land
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:48
yeah. very neat
James Forbes
@JAForbes
Mar 22 2017 03:48
or we can take any library, even a highly internally mutable library
with fantasy land, we need the library author to actually know about fantasy land and add special keys to their prototype etc
and its also worth noting, you can implement both, and many libraries do
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:52
With Ramda, I was able to do the transformation I need in 10 lloc
I'm betting making a type for that is overkill
especially since it's a one time thing
It's just that it's still a pretty annoying 10 lines
James Forbes
@JAForbes
Mar 22 2017 03:54
yeah particularly when your focused on avoiding kb's
its certainly nice when you can assume ramda as a dependency, e.g. in an application as opposed to a library
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:54
I actually can't use Ramda on this :)
James Forbes
@JAForbes
Mar 22 2017 03:55
I think if we had Array::flatMap we could write some pretty amazing monadic code in vanilla JS when we don't want to pull in libraries
Johnny Hauser
@m59peacemaker
Mar 22 2017 03:55
but worst case, I'll pull it off with other npm modules
James Forbes
@JAForbes
Mar 22 2017 03:55
I mean you could just write flatMap, but its nice when its a method
lately I just stuff things in arrays so I can map over them for convenience
and avoiding null checks etc
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:01
While I'm thinking I won't be using it, I still want to try to make a type for this for practice.
So far I just ended up with the same code I already had plus some useless nesting lol
James Forbes
@JAForbes
Mar 22 2017 04:04
haha yeah its good practice
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:20
So, you can't R.map(fn, MyStaticLandType)
but on the other hand, you don't need to?
no, that doesn't make sense
you need to be able to call whatever map is appropriate to the type and you don't always know what kind of type you'll have by then, do you?
Dylan Falconer
@Falconerd
Mar 22 2017 04:31
hey guys, I hope you don’t mind me asking really rookie questions in here. If not, I’d like to know how to solve this particular problem and if I should even be using ramda to do so:
const selected = [
  {
    id: 1
  }
];

const list = [
  { id: 1 },
  { id: 2 },
  { id: 3 },
];

// Do some shenanigans
// => [1]
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:32
oh yeah, sure
just a sec
I take it there could be more than one in selected ?
and also that there can be other properties in the list objects?
Dylan Falconer
@Falconerd
Mar 22 2017 04:33
yeah, that’s the idea
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:33
otherwise, [selected[0].id] lololol
nailed it =D
Dylan Falconer
@Falconerd
Mar 22 2017 04:33
haha yeah
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:34
but yeah, just a minute.
oh, also
will you ever select by anything other than id?
Dylan Falconer
@Falconerd
Mar 22 2017 04:34
in this instance, no
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:34
k
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:43
sorry, I'm terribly slow still
someone might be me to it
getting there, though
Dylan Falconer
@Falconerd
Mar 22 2017 04:44
there’s no rush, it’s just an interesting problem which i would usually solve in a few steps.
I’m just thinking there is probably a better way
James Forbes
@JAForbes
Mar 22 2017 04:45
@m59peacemaker sorry was afk, yeah ramda kind of is static land on its own if you think about it
but it doesn't work against other static land implementations
you need your own map
it'd be cool to be able to parameterize the static structure and get other functionality for free
I think someone here was experimenting with that but I don't remember
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:48
@Falconerd If it helps, I'm messing with filter any prop('id') equals
not quite getting it, though
Dylan Falconer
@Falconerd
Mar 22 2017 04:52
@m59peacemaker Cheers, I am still messing around with it as well
Johnny Hauser
@m59peacemaker
Mar 22 2017 04:56
filter(pipe(
  converge(contains, [ prop('id'), _ => map(prop('id'))(selected) ])
))(list)
probably can be done much better
Dylan Falconer
@Falconerd
Mar 22 2017 04:56
i’m starting to think this is a non-problem anyway…
selected.map(a => a.id);
i can’t remember what i was trying to solve now, i’m sorry. i’m going to try out your solution and see if that helps me remember
right, that gets the full object from the list, instead of just the id. so that could be useful too
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:00
I'm doing it much better
way better
just a sec
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:14
all I need to do is turn {a: 123, b: 456} into [{a: 123}, {b: 456}]
I know it's toPairs map and objOf
the hard thing for Ramda noobs like myself is figuring out how to connect them
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:20
map(apply(objOf))(toPairs(item))
Denis Stoyanov
@xgrommx
Mar 22 2017 05:21
@m59peacemaker
compose(map(apply(objOf)), toPairs)({a: 123, b: 456})
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:22
ty!
I was just trying to work out how to get toPairs in the right place
@Falconerd
var isIn = flip(contains)
var matchesAnyItems = (items, item) => {
  var itemParts = compose(map(apply(objOf)), toPairs)(item)
  return any(isIn(items))(itemParts)
}
matchesAnyItems([{id: 1}], {a: 'b', id: 1})
and now to make it point free...
Dylan Falconer
@Falconerd
Mar 22 2017 05:26
hmm
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:26
that's a degree smarter than you may desire
It can match on any k/v
Dylan Falconer
@Falconerd
Mar 22 2017 05:26
yeah, i generally prefer to write like that
i noticed all the ramada examples are very specifically suited
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:27
matchesAnyItems([{a: 'b'}], {a: 'b', id: 1})
Sorry, that's incomplete, you filter on that
I'm going to perfect the whole example here soon!
this is great practice
Dylan Falconer
@Falconerd
Mar 22 2017 05:28
haha awesome!
Denis Stoyanov
@xgrommx
Mar 22 2017 05:29
@m59peacemaker also :smile:
converge(zipWith(objOf), [keys, values])({a: 123, b: 456})
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:29
hah neat
that is better!
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:38
grrr. can't think of a way to make it point free without making it actually ugly
var isIn = flip(contains)
var matchesAnyItems = curry((items, item) => {
  var itemParts = converge(zipWith(objOf), [keys, values])(item)
  return any(isIn(items))(itemParts)
})
filter(matchesAnyItems(selected))(list)
The next step would be to make isIn smarter
Right now, you can only match on one k/v
{foo: 'bar', baz: 'qux'} should match {foo: 'bar', baz: 'qux', id: 20} would be cool
James Forbes
@JAForbes
Mar 22 2017 05:52
@m59peacemaker tried playing with lenses? They can be pretty helpful for point free
Johnny Hauser
@m59peacemaker
Mar 22 2017 05:53
I use them for stuff, yeah
maybe not in that way, though. Not sure how in that case.
Johnny Hauser
@m59peacemaker
Mar 22 2017 06:36
@Falconerd smart matching: https://goo.gl/Wg1BTc
var hasPair = curry((pair, item) => {
  var args = compose(nth(0), toPairs)(pair)
  return apply(propEq, args)(item)
})
var hasPairs = curry((pairs, item) => {
  var p = converge(zipWith(objOf), [keys, values])(pairs) 
  return all(hasPair(__, item))(p)
})
var matchesSomeCriteria = curry((criteria, item) => any(hasPairs(__, item))(criteria))
Goodnight!
Dylan Falconer
@Falconerd
Mar 22 2017 06:37
Thanks @m59peacemaker !
Good job
James Forbes
@JAForbes
Mar 22 2017 06:48

I think we can move itemParts up

var isIn = flip(contains)
var itemParts = converge(zipWith(objOf), [keys, values])
var matchesAnyItems = curry((items, item) => {
  return any(isIn(items))(itemParts(item))
})

Then useWith could help (I think)

const matchesAnyItems = useWith(any, [isIn, itemParts])
untested
Raine Virta
@raine
Mar 22 2017 11:48
how do functional people prefer to express sql queries in node? any favorite libraries etc.
James Forbes
@JAForbes
Mar 22 2017 11:51
@raine I've tried a few things
@raine I've got a require hook, I do as much as I can in SQL, I don't see any value in not writing SQL directly
Then you can also create functions/views on the db and just call them
Raine Virta
@raine
Mar 22 2017 11:52
knex seems too fluent/methody but i have minimal experience in sql. in mongo i've sort of liked that queries are data
James Forbes
@JAForbes
Mar 22 2017 11:53
for the require hook I parameterize it using pg-promise but I store all the parameters ahead of time in a with so there aren't variables spread throughout the query
Raine Virta
@raine
Mar 22 2017 11:54
can you elaborate on that?
James Forbes
@JAForbes
Mar 22 2017 11:54
e.g.
with args(user_id) as (
   (select $[user_id])
   ,(select $[company_id])
)

select etc from whatever, args where whatever.user_id = args.user_id
So that $[] syntax is just pg-promise's built in escaping syntax
but I centralize it, so I don't have string interpolation spread throughout the query
then I can write and test the entire query in pg-admin, and just swap out the args query when I save it to a file
it can help to have some functions for setting up your env, basically dump some DELETE/CREATE/INSERT statements in a setup function, and you can call that as you build up queries
another tip: use selects everywhere, even inserts, because they're super testable

so

insert into whatever (a,b,c) select 1,2,3 from something

instead of

insert into whatever (a,b,c) values (1,2,3)

values is just sugar for select but having select already ready to go makes for easy extensions if you want to do something more relational

e.g. build a table out of another table
James Forbes
@JAForbes
Mar 22 2017 12:00

This is my require hook:

require('require-hacker').hook('sql', function(filepath){

  const fs = require('fs')
  const sql = fs.readFileSync(filepath).toString('utf8')

  return `module.exports = \`${sql}\``
})

Super basic.

pg-promise has a queryfile option, I just wrote the above first and never migrated because this worked
Raine Virta
@raine
Mar 22 2017 12:01
okay i see, you have queries in sql files instead of directly in code
James Forbes
@JAForbes
Mar 22 2017 12:01
yeah as much as possible
node basically becomes "here's some stuff from the network" and that's it
oh then of course, sending it back to the client
I've got one big function that whitelists, and validates, filters anything that comes back from the db, which leaves individual endpoint code as just a sql file
Raine Virta
@raine
Mar 22 2017 12:02
why do you prefer that require hook over just reading files? it's a bit less verbose i guess
James Forbes
@JAForbes
Mar 22 2017 12:03
no reason, reading files would be cool too
I'll post some sample code in a gist
Raine Virta
@raine
Mar 22 2017 12:05
I'm confused about the with args(user_id) example, but that might just be my lack of sql knowledge
James Forbes
@JAForbes
Mar 22 2017 12:08
Yeah they are the most important and least used feature
Think of it as queries that exist within an expression, and last for the duration of that statement, and you can reference them in later queries
you can use them to generate data to insert into a table, or insert into multiple tables at once, or just turn one big query into a composition of smaller ones
Few more important things for postgres in particular if you want to do stuff like this
you need to be able to generate uuid's in sql, so you need to activate the pg crypto extension
you just do that by going: CREATE EXTENSION IF NOT EXISTS pgcrypto
The other thing you'll want to do is make all foreign key's lazy, so it only verifies them at the end of the statement
in pg admin when you create the foreign key just click the DEFERRABLE and INITIALLY DEFERRED checkboxes
but only for foreign keys not primary keys
and that's it your golden
you can now do some seriously involved compositional sql
James Forbes
@JAForbes
Mar 22 2017 12:13
you'll probably notice in that gist everything is pure, right up until the end
so you can just replace that select OK with whatever you want to test the output is ok
Raine Virta
@raine
Mar 22 2017 12:15
right you meant testable as in that queries are valid SQL which would be a bit difficult to verify if the queries were in conjunction with application code
and is there more to it than just valid SQL
James Forbes
@JAForbes
Mar 22 2017 12:16
testable because its all pure, you can run it as many times as you want and its referentially transparent, so you can move the select out and it will still make sense
Raine Virta
@raine
Mar 22 2017 12:17
what value does that have?
James Forbes
@JAForbes
Mar 22 2017 12:17
@raine its easier to follow a smaller query than a larger one, and you might make it a view and reuse it in another query
Raine Virta
@raine
Mar 22 2017 12:18
I see
James Forbes
@JAForbes
Mar 22 2017 12:18
if your data generation is bound to the insert, you need to clean the db every time you want to retest
it adds up quickly, it quickly becomes frustrating
Raine Virta
@raine
Mar 22 2017 12:18
do you happen to have a minimal example of how this sql stuff glues to pg-promise?
James Forbes
@JAForbes
Mar 22 2017 12:19
ok so that gist is just a sql file in a directory next to an endpoint
const SQL = {
    auth_permissions_from_invite:
        require('./groups/auth_permissions_from_invite.sql')
    ,group_users_from_group_ids:
        require('./groups/group_users_from_group_ids.sql')
}
now they're just strings
well technically they are a node module that exports a string, but it evaluates to a record of strings
then you can see in that gist it takes 2 args
so we just run it like db.query( SQL.auth_permissions_from_invite, { organization_id, user_id })
that's it, that's the integration
I mean to get up and running that's it
you'll also want a work flow for dumping your schema to a file and committing it with your branch, and you'll want some convenience scripts for recreating the db schema if your jumping across branches or deploying etc

and then migration just sucks, but that's a general problem.

I'm working on an experimental approach to migration but its not tested enough yet to get into

James Forbes
@JAForbes
Mar 22 2017 12:24
but the standard approach is, have some scripts to go up and down in schema versions
I think the model is fundamentally broken but its the state of the art
Raine Virta
@raine
Mar 22 2017 12:27
so when you do FROM args it makes it's so that arguments passed with db.query "go through" that args with/function and are usable through args for the rest of the query
is the mechanic such that because the args happens to be directly after FROM, the arguments are passed to with args?
Raine Virta
@raine
Mar 22 2017 12:33
this is a bit similar to what you have http://vitaly-t.github.io/pg-promise/QueryFile.html
James Forbes
@JAForbes
Mar 22 2017 12:48
sorry was away for a bit

@raine yeah that's what I was ranting about earlier

pg-promise has a queryfile option, I just wrote the above first and never migrated because this worked

definitely advantageous to use that instead
I just haven't yet
Kurt Milam
@kurtmilam
Mar 22 2017 12:50
Is there an existing name or function that does the following:
alwaysCallFn = fn => R.compose( R.call, R.always( fn ) )
James Forbes
@JAForbes
Mar 22 2017 12:50

@raine re args, you could think of it that way.

How it's optimized varies depending on context, but I think the way we're meant to think about is like so

It runs the query, it stores the result set as a table expression.

You can then query that result set just like any other table.

I think in some cases if there's a select, and its never used it's never run
and in other cases, if the select is only used once its essentially inlined as a sub query

but I'd think of with args as ( ... )

More like const args = { ... } for all intents and purposes

I mean technically its more like:
const args = [{...}, ...]
because args.organization_id could be many rows later if I wanted
@kurtmilam what is the usage?
@raine at any time you can put EXPLAIN in front of a query and it will graph what is actually happening
Kurt Milam
@kurtmilam
Mar 22 2017 12:55
@JAForbes I'm using it with flyd streams.
to make them composable, for instance:
James Forbes
@JAForbes
Mar 22 2017 12:55
I think you might want nAry(0, stream)
Kurt Milam
@kurtmilam
Mar 22 2017 12:55
R.compose( alwaysCallFn( stream ), stream, R.flip( lens )( stream() ) )
huh, let me try that.
James Forbes
@JAForbes
Mar 22 2017 12:56
yeah its a pain that
Kurt Milam
@kurtmilam
Mar 22 2017 12:56
stream is a flyd stream above.
Raine Virta
@raine
Mar 22 2017 12:56
so you want to call stream without arguments basically?
Kurt Milam
@kurtmilam
Mar 22 2017 12:57
@JAForbes that seems to do the trick, thanks.
James Forbes
@JAForbes
Mar 22 2017 12:57
sweet
Kurt Milam
@kurtmilam
Mar 22 2017 12:58
@raine Yeah, I'm working with flyd streams, and calling stream(1) doesn't return 1.
James Forbes
@JAForbes
Mar 22 2017 12:58
it'd be nice to have an explicit get/set
Kurt Milam
@kurtmilam
Mar 22 2017 12:58
So I want to be able to compose the stream and get the value out after I set it.
James Forbes
@JAForbes
Mar 22 2017 12:58
wait I think I'm missing something
ahhh
yeah ok that works
was just thinking could you do it in a tap
Raine Virta
@raine
Mar 22 2017 12:59
() => stream() is maybe not a bad option either
James Forbes
@JAForbes
Mar 22 2017 12:59
tap(stream)
yeah @raine :thumbsup:
Kurt Milam
@kurtmilam
Mar 22 2017 13:00
@JAForbes I noticed that mithril stream returns the value, so `mithrilStream(1)' returns 1, which is nice for composition. I haven't checked what flyd stream returns, but it's not 1.
James Forbes
@JAForbes
Mar 22 2017 13:00
tap(stream) should work too though
@kurtmilam yeah it returns itself
which is actually really useful
I didn't know mithril did that which is a shame
but I guess that's what prop's did so its a compatibility thing
tap(stream) would let you remove the alwaysCallFunction and the nAry
in that specific use case
nAry(0) or what @raine raine suggested makes sense if you were getting only and not setting
Kurt Milam
@kurtmilam
Mar 22 2017 13:01
:D I was wondering which was better. I guess I got used to the mithril way, then needed to figure out how to refactor the code to work with flyd. Will try tap(stream)
James Forbes
@JAForbes
Mar 22 2017 13:01
but seeing as your setting, I think tap works best
R.compose( tap(stream), R.flip( lens ))
why are you flipping the lens? that's interesting
Raine Virta
@raine
Mar 22 2017 13:04
@JAForbes do you use pg-monitor?
Kurt Milam
@kurtmilam
Mar 22 2017 13:05
interesting, so tap(stream) replaces alwaysCallFn( stream ), stream. That's definitely nicer.
let me see why I'm flipping lens.
const updateStreamProp =
  R.curry( ( stream, lens ) =>
             R.compose( R.tap( stream ), R.flip( lens )( stream() ) )
         )
James Forbes
@JAForbes
Mar 22 2017 13:06
@raine haha no but maybe I should, I just configure the lib to log all queries in dev with a prefix
So the node server is just spitting them out and I redirect that to a log file and run less +F against it
James Forbes
@JAForbes
Mar 22 2017 13:07
yeah its a good wiki
I just didn't need it, I haven't been in the situation where I didn't know what was going in the db
Kurt Milam
@kurtmilam
Mar 22 2017 13:08
I'm flipping it so I can send in the stream first.
James Forbes
@JAForbes
Mar 22 2017 13:08
but I think its probably a good idea, I think anything they recommend is a good idea
@kurtmilam can you post usage (out of interest)
Kurt Milam
@kurtmilam
Mar 22 2017 13:16
There was a historical reason for flipping it, but it seems I've abstracted that reason away, in the meantime.
wait you're taxing my brain. lemme take a look at it :)
ok, I was wrong, I currently still need to flip the lens.
seems straightforward - this is part of the lensedStream stuff I was playing around with last week.
const setLensedStream = updateStreamProp( stream, L.set( payloadOptic( optic ) ) )
Kurt Milam
@kurtmilam
Mar 22 2017 13:24
I'm afraid my brain is a bit mushy today. Too many beers at a friend's moving away party on Monday. Let me see if I can try to explain it clearly.
James Forbes
@JAForbes
Mar 22 2017 13:24
wait I think I get it
your binding this function to a particular stream and a particular property in a state object, so its easy to use later
is that right?
Kurt Milam
@kurtmilam
Mar 22 2017 13:26
that's correct
thanks for the rescue :D
James Forbes
@JAForbes
Mar 22 2017 13:27
so when someone calls setLensedStream, they write to the stream via the lens
so you pass in some data, the lens returns the complete structure and you write that to the stream
Kurt Milam
@kurtmilam
Mar 22 2017 13:27
exactly
we talked about it a little in the mithril room last week
James Forbes
@JAForbes
Mar 22 2017 13:28
yeah
what's payloadOptic(optic)
Kurt Milam
@kurtmilam
Mar 22 2017 13:29
Well, I started with just one state object whose childNodes were already state data.
Then I made state into: { streamsRegister:{}, payload:{}}
So each stream is registered in streamsRegister with the object path as the key while the state data is in payload. I did that as a way of caching the streams for reuse, and to make sure I didn't end up with multiple streams pointing at the same slice of state data.
James Forbes
@JAForbes
Mar 22 2017 13:31
ah ok
Kurt Milam
@kurtmilam
Mar 22 2017 13:32

I realized that if I did

user = lensedStream( [ 'Users', 'item' ] )
user1 = lensedStream( [ 'Users', 'item' ] )

I'd have two separate streams pointing to the same slice of state data.

and that would lead to

user( 'John' )
user1( 'Mary' )
user() // `John`

So, I couldn't guarantee that the streams were in sync with the state.

Now,

user = lensedStream( [ 'Users', 'item' ] )
user1 = lensedStream( [ 'Users', 'item' ] )

user and user1 will contain copies of the same stream, so they're always in sync with the state.

James Forbes
@JAForbes
Mar 22 2017 13:35
yeah I see
Kurt Milam
@kurtmilam
Mar 22 2017 13:36
mostly having fun distracting myself from actual stuff I should be working on. I'm trying to figure out whether there's anything promising in that lensedStreams concept.
I was reading a bit about calmm-js (the project that partial.lenses comes from, and they have the concept of lensedAtoms. Was trying to see whether I could come up with a similar, workable concept for lensedStreams.
James Forbes
@JAForbes
Mar 22 2017 13:40
yeah it will be fun to compare notes after our different takes have matured a bit
I've gone towards having 1 stream for the state, as opposed to 1 stream per property/lens, that's just come from my intuition with streams generally though (before this lens madness infected me)
Kurt Milam
@kurtmilam
Mar 22 2017 13:41
:thumbsup:
Raine Virta
@raine
Mar 22 2017 13:51
@JAForbes thanks for the psql advice btw, i'll probably refer back to the conversation as i become more familiar with it
Johnny Hauser
@m59peacemaker
Mar 22 2017 13:54
@raine I think the answer to your original question is sql-concat
Kurt Milam
@kurtmilam
Mar 22 2017 13:54
@JAForbes I'm playing with one stream for state but mashing it up with lenses that return slices of the object held in the state stream where those slices are held inside their own streams. It makes for some nice abstractions, but I have to see what sort of unexpected difficulties it leads to.
basically, I started out with one stream for state and used lenses to operate on the object in that stream, but there was a bit of boilerplate I was trying to abstract away.
James Forbes
@JAForbes
Mar 22 2017 14:12
@raine my pleasure, hit me up anytime too
yeah @kurtmilam I remember you mentioning that you may as well return a stream when you were working on a problem a while ago
because the api mimicked a stream anyway
I'd really like to see where it goes
It worked out well for flyd's end streams
Galileo Sanchez
@galileopy
Mar 22 2017 14:23
R.evolve is messing with my objects

input is a daggy.tagged object
function is

R.compose(
                R.evolve({
                    Reason: R.prop(R.__, events),
                }),
                R.tap(function () {
                    console.log(arguments);
                })
            )

this outputs { '0': { Data: 0, Reason: 32, Mode: 1 } }
however

R.compose(
                R.tap(function () {
                    console.log(arguments);
                }),
                R.evolve({
                    Reason: R.prop(R.__, events),
                })
            )

makes the tagged constructor visible

{ Data: 0,
  Reason: 'IP changed/connection up',
  Mode: 1,
  toString: '[object Undefined]',
  constructor: 
   { [Function]
     toString: [Function: typeRepToString],
     prototype: 
      { toString: [Function: tagged$toString],
        constructor: [Circular] },
     is: [Function: isType],
     '@@type': 'Transmission',
     Grammar: [ [Object], [Object], [Object] ],
     parser: [Function],
     parse: [Function] },
  EventCode: 32 }
Galileo Sanchez
@galileopy
Mar 22 2017 14:31
I ended up using applySpec and listing all the other objects
Johnny Hauser
@m59peacemaker
Mar 22 2017 16:24
If I understand correctly, Ramda REPL is brilliant for putting all the code in the url and then making goo.gl save it with the short url. There is seriously no url length limit!?
Galileo Sanchez
@galileopy
Mar 22 2017 16:50
I think there is a technical limit
2,083 characters
Galileo Sanchez
@galileopy
Mar 22 2017 16:59
However I see that there's a small catch
the ramda repl url is http://ramdajs.com/repl/?v=0.23.0#
it ends in a #
Any information that appears after the first hash symbol in a URL is referred to as the fragment identifier – sometimes also called an anchor tag. By default, the fragment identifier is interpreted only by the local web browser and is typically not passed to the remote web server. For example, the following two links would both be considered requests for the same document by the web server:
Galileo Sanchez
@galileopy
Mar 22 2017 17:08
so the browser limit of 2038 chars is bypassed, and the code is a html fragment, and I don't know if there is a limit on the fragment identifier size
Matt Ross
@amsross
Mar 22 2017 20:22
This message was deleted
am I misunderstanding something here:
const data = { stats: {ranking:2} };
const aLens = R.converge(R.lens, [
  R.path,
  R.assocPath,
])(["stats"]);
const bLens = R.lens(R.path(["stats"]), R.assocPath(["stats"]))

console.log("a", R.view(aLens, data)); // undefined
console.log("b", R.view(bLens, data)); // {"ranking": 2}
Matt Ross
@amsross
Mar 22 2017 20:24
I would assume that I could use converge to apply a shared value to my getter and setter to produce a lens
I’m familiar with that, I’ve removed any of the logic peculiar to the use-case to find the simplest case where the problem can be seen
you could assume that different mutations are being done to the provided path ([“stats”]) in such a way that the getter and setter (path, assocPath) access different property paths
Robert Mennell
@skatcat31
Mar 22 2017 20:26
I'm confused on why you're using a path for something that is at base level? Shouldn't prop and assoc work just fine there? Or are you saying you want to possibly go deeper?
Matt Ross
@amsross
Mar 22 2017 20:29
I think the lens will be used to get and set on an object that has many different paths which must all be accessed and set according to the rules in each array element passed to converge
this is a problem from a coworker,. the fact that R.converge(R.lens, []) isn’t working is what is confusing/interesting to me, not the rightness of the approach. he can figure that out
I have a feeling that this will all be mapped through to generate a composition or something to then pass some real data objects through
Piet Vandeput
@piet-v
Mar 22 2017 20:32
Hi guys, trying to convert lodash function using _.flatMapDeep to ramda. Anyone know how I can best implement it?
Robert Mennell
@skatcat31
Mar 22 2017 20:32
what your a lens is versus your b lens:
function (t,r){return n.apply(this,arguments)}
function (r){return function(e){return ae(function(t){return n(t,e)},r(t(e)))}}
Daniel Rodríguez
@sadasant
Mar 22 2017 20:33
Anything deep can be done with functions like this: ramda/ramda#2133
this needs to be discussed by the community, but once we reach an agreement we can easily have functions for:
depthFold(reducer, accumulator, target)
breadthFold(reducer, accumulator, target)
depthFoldRight(reducer, accumulator, target)
breadthFoldRight(reducer, accumulator, target)
Piet Vandeput
@piet-v
Mar 22 2017 20:35
so no ez way to do it right now? rip
Daniel Rodríguez
@sadasant
Mar 22 2017 20:35
you can write your own recursive function in the mean time
Piet Vandeput
@piet-v
Mar 22 2017 20:35
I guess, it's what i had before I converted it to lodash some months ago >.<
Daniel Rodríguez
@sadasant
Mar 22 2017 20:36
well, you can also copy depthReduce from my pr
it's fully tested, I can tell you how to use it etc
Piet Vandeput
@piet-v
Mar 22 2017 20:36
Sounds like I could use it for my usecase, deepfiltering on values with exclusion of certain keys >.<
Daniel Rodríguez
@sadasant
Mar 22 2017 20:37
yep, I've been using that
it stops with empty [], and continues with non empty []
it also doesn't use recursion, so no max stack calls exceeded
Matt Ross
@amsross
Mar 22 2017 20:39
@skatcat31 I see that the resulting function isn’t the same, but it isn’t clear why that is, given that these are the same:
R.add(R.inc(2), R.inc(2)) // 6
R.converge(R.add, [R.inc,  R.inc])(2) // 6
Piet Vandeput
@piet-v
Mar 22 2017 20:40
any fast way to replace that curry3 import in ur PR?
R.curryN(3) ?
Daniel Rodríguez
@sadasant
Mar 22 2017 20:40
yeah something like that
or a => b => c => {}
Matt Ross
@amsross
Mar 22 2017 20:40

or that both of these:

R.converge(R.add, [
  R.inc,
])(2)
R.add(R.inc(2))

result in this

function n(r){return 0===arguments.length||b(r)?n:t.apply(this,arguments)}
Daniel Rodríguez
@sadasant
Mar 22 2017 20:41
@piet-v but comment on that PR and tell your peers to add reactions :+1: :joy: the most of us are there, chances of having this properly done are increased
I'd rather compromise myself to maintain this opensource and community checked than keep having this inside our codebase
Piet Vandeput
@piet-v
Mar 22 2017 20:41
one question
Daniel Rodríguez
@sadasant
Mar 22 2017 20:42
I'm here :+1:
Piet Vandeput
@piet-v
Mar 22 2017 20:42
if it stops on []
if the first value I encounter is an excluded key my acc will return []
so am I fked then?
Daniel Rodríguez
@sadasant
Mar 22 2017 20:42
no no, just return [acc]
acc is [], so it will be [[]]
Piet Vandeput
@piet-v
Mar 22 2017 20:43
ah nvm, can just return '' xd
Daniel Rodríguez
@sadasant
Mar 22 2017 20:43
let's say, if (!matches) return [acc]
if (doStop) return []
Piet Vandeput
@piet-v
Mar 22 2017 20:44
think the acc will be something like R.append(value)(acc)
Daniel Rodríguez
@sadasant
Mar 22 2017 20:44
the unit tests in the PR are pretty deep, there's an unfold implemented with depthReduce, and a deep map also implemented with depthReduce
yes, but remember that we grab the [0] result of what you return
Piet Vandeput
@piet-v
Mar 22 2017 20:44
ah
Daniel Rodríguez
@sadasant
Mar 22 2017 20:44
so, return [R.append(value)(acc)]
Denis Stoyanov
@xgrommx
Mar 22 2017 20:44
:point_up: March 22, 2017 10:40 PM what is your expected result?
Piet Vandeput
@piet-v
Mar 22 2017 20:44
rip :D
Daniel Rodríguez
@sadasant
Mar 22 2017 20:45
@piet-v if you want, write me privately to stop hijacking this chat
Johnny Hauser
@m59peacemaker
Mar 22 2017 20:50
@galileopy At least one browser I know will execute a url 100,000 characters long. I was referring to how long of a url google will save/shorten for you
That's potentially a lot of free db space!
You hypothetically could translate all of your public API data into urls and have goo.gl save it for you lololol
Kurt Milam
@kurtmilam
Mar 22 2017 21:01
@m59peacemaker I've run into limits trying to create a goo.gl short link from the repl. I haven't counted the maximum allowed url length yet.
Robert Mennell
@skatcat31
Mar 22 2017 21:01
@xgrommx he's attempting to use converge to build a lensPath
Johnny Hauser
@m59peacemaker
Mar 22 2017 21:37

why does groupBy do:

reduceBy(function(acc, item) {
  if (acc == null) {
    acc = [];
  }
  acc.push(item);
  return acc;
}, null

rather than

reduceBy(flip(append), []

https://github.com/ramda/ramda/blob/v0.23.0/src/groupBy.js#L45-L51

Brad Compton (he/him)
@Bradcomp
Mar 22 2017 21:53
My guess is performance. The second one would construct a new array every time.
As somebody who's used groupBy on upwards of 80k item arrays, I appreciate the structural sharing :stuck_out_tongue:
Piet Vandeput
@piet-v
Mar 22 2017 21:56
Anyone have an idea for a clean ramda version of:
const substrings = ['a', 'b', 'c']
const stringsToTest = ['lol', 'haha', 'rofl']

const anyStringContainsAnySubString = ??? // (substrings, stringsToTest) => Bool
have this working code but was wondering if anyone knows cleaner way to do it
const anyStringContainsAnySubString = (searchValues, actualValues) => {
  return searchValues.every(searchValue => {
    return R.any(actualValue => actualValue.toString().toUpperCase().includes(searchValue.toUpperCase()))(actualValues)
  })
};
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:21
@ram-bot
const substrings = ['a', 'b', 'c']
const stringsToTest = ['lol', 'haha', 'rofl']

any(anyPass(map(contains)(substrings)), stringsToTest)
ram-bot
@ram-bot
Mar 22 2017 22:21
true
Johnny Hauser
@m59peacemaker
Mar 22 2017 22:21
@Bradcomp hmmm.. I don't see it. It looks to me like you will always have an array of items to iterate and you will always create an array to append those items to as you iterate.
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:21
:point_up: That's pretty ugly though ;)
Piet Vandeput
@piet-v
Mar 22 2017 22:21
thinking of using unionWith and contains
Johnny Hauser
@m59peacemaker
Mar 22 2017 22:21
I even reason that append is more efficient because it doesn't have the if
What am I missing?
OHHH
mutation
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:22
@m59peacemaker You're creating a single array and just pushing values to it. Because JS is pass by reference for arrays
Johnny Hauser
@m59peacemaker
Mar 22 2017 22:22
yep yep yep
just clicked
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:22
Sorry, typd that out before you finished ;)
Johnny Hauser
@m59peacemaker
Mar 22 2017 22:23
So, you could do flip(mutativePush, [] though, right?
Piet Vandeput
@piet-v
Mar 22 2017 22:23
alright think I got it figured out
or not lol
ok, lol got it working almost but tell me why does
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:28
@ram-bot
const substrings = ['a', 'b', 'c']
const stringsToTest = ['lol', 'haha', 'rofl']

any(apply(contains), xprod(substrings, stringsToTest))
ram-bot
@ram-bot
Mar 22 2017 22:28
true
Piet Vandeput
@piet-v
Mar 22 2017 22:28
intersectionWith give (a, b) to the comparator and unionWith give (b,a) ?
Johnny Hauser
@m59peacemaker
Mar 22 2017 22:28
reduceBy(push, [] works
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:29
@m59peacemaker I like that version
@piet-v I think it's some implementation details for the set stuff. They optimize based on which list is shorter
But in this case both are the same so...
Piet Vandeput
@piet-v
Mar 22 2017 22:31
ah crap, forgot to specify
Johnny Hauser
@m59peacemaker
Mar 22 2017 22:31
oh heck, maybe push doesn't work!
Piet Vandeput
@piet-v
Mar 22 2017 22:31
all the substring must be found for it to return true
x)
my bad! :blush:
RIP, it works but it checks if ANY substr is found instead of ALL
const StringsContainAll = R.pipe(R.intersectionWith(R.contains), R.length);
Piet Vandeput
@piet-v
Mar 22 2017 22:37
@Bradcomp ur xprod version also does an ANY for the substrings :D
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:41
Yeah, it does
Piet Vandeput
@piet-v
Mar 22 2017 22:41
aight, got it
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:41
My first solution would work if you swapped the anyPass for an allPass
Piet Vandeput
@piet-v
Mar 22 2017 22:41
const stringsContainAllSubstrings = (searchValues, actualValues) => R.pipe(R.intersectionWith(R.contains), R.length, R.equals(searchValues.length))(searchValues, actualValues);
I guess urs is cleaner though :D
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:43
I dunno about that ;)
Piet Vandeput
@piet-v
Mar 22 2017 22:45
now to figure out a way to make it casing independent x)
guess putting usewith around the contains
Sebastian Andres
@sebandres
Mar 22 2017 22:53
Hello all! :D
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 22:54
:wave:
Sebastian Andres
@sebandres
Mar 22 2017 22:56
Not sure if we have guidelines here as to what we can post but I've been scratching my head around composeP's result when a function takes no parameters and returns a promise, is this the right channel to try and figure it out?
Sebastian Andres
@sebandres
Mar 22 2017 23:04

@ram-bot ```
const doSomethingElse = (anotherValue: string) => Promise.resolve(anotherValue)

const doSomething = (value: string) => Promise.resolve(value)

const doSomethingWithValue = R.partial(doSomething, ['Yay!'])

const doEverything = R.composeP(doSomethingElse, doSomethingWithValue)

doEverything()
```

Ian Hofmann-Hicks
@evilsoft
Mar 22 2017 23:04
where is that function in your chain? is it at the head or somewhere in the tail?
Sebastian Andres
@sebandres
Mar 22 2017 23:04
:(
How should I send code to the bot?
well the issue I am seeing here (and it might just be the typings given I am using typescript) is that in the case I sent above the 'doEverything' function actually expects 1 argument when it shouldn't expect any
I end up having to do doSomething([insert garbage here]) otherwise the compiler complains about missing param
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:08
@ram-bot
const doSomethingElse = (anotherValue: string) => Promise.resolve(anotherValue)
const doSomething = (value: string) => Promise.resolve(value)
const doSomethingWithValue = R.partial(doSomething, ['Yay!'])
const doEverything = R.composeP(doSomethingElse, doSomethingWithValue)
doEverything()
ram-bot
@ram-bot
Mar 22 2017 23:08
Unexpected token :
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:09
You just forgot the newline ;)
Sebastian Andres
@sebandres
Mar 22 2017 23:10

@ram-bot ```
const doSomethingElse = (anotherValue: string) => Promise.resolve(anotherValue)

const doSomething = (value: string) => Promise.resolve(value)

const doSomethingWithValue = R.partial(doSomething, ['Yay!'])

const doEverything = R.composeP(doSomethingElse, doSomethingWithValue)

doEverything()
```

@ram-bot
const doSomethingElse = (anotherValue: string) => Promise.resolve(anotherValue)

const doSomething = (value: string) => Promise.resolve(value)

const doSomethingWithValue = R.partial(doSomething, ['Yay!'])

const doEverything = R.composeP(doSomethingElse, doSomethingWithValue)

doEverything()
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:10
Are you using typescript or flow or something?
Sebastian Andres
@sebandres
Mar 22 2017 23:10
do I use 'R.' or is this not necessary (sorry first time here!)
I am using typescript
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:11
You don't have to use R. for the ram-bot
Sebastian Andres
@sebandres
Mar 22 2017 23:11
cool, thanks @Bradcomp
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:11
But it doesn't speak TS
Sebastian Andres
@sebandres
Mar 22 2017 23:11
let's see if I can get this to run
Robert Mennell
@skatcat31
Mar 22 2017 23:12
@ram-bot r.view
ram-bot
@ram-bot
Mar 22 2017 23:12
r is not defined
Robert Mennell
@skatcat31
Mar 22 2017 23:12
@ram-bot R.view
ram-bot
@ram-bot
Mar 22 2017 23:12
[Function: f2]
Sebastian Andres
@sebandres
Mar 22 2017 23:12
@ram-bot
const doSomethingElse = (anotherValue) => Promise.resolve(anotherValue)
const doSomething = (value) => Promise.resolve(value)
const doSomethingWithValue = partial(doSomething, ['Yay!'])
const doEverything = composeP(doSomethingElse, doSomethingWithValue)
doEverything()
Robert Mennell
@skatcat31
Mar 22 2017 23:12
you don't have too, but you can so copy and pasting from REPL won't require modification right?
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:13
Usually, yeah
@ram-bot
const doSomethingElse = (anotherValue) => Promise.resolve(anotherValue)
const doSomething = (value) => Promise.resolve(value)
const doSomethingWithValue = partial(doSomething, ['Yay!'])
const doEverything = composeP(doSomethingElse, doSomethingWithValue)
doEverything()
ram-bot
@ram-bot
Mar 22 2017 23:13
Promise { <pending> }
Sebastian Andres
@sebandres
Mar 22 2017 23:13
how come it works when you send it @Bradcomp ?
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:14
@sebandres Not sure why it isn't listening to you
Ian Hofmann-Hicks
@evilsoft
Mar 22 2017 23:14
So it must have something to do with TS, I can add .then(console.log.bind(console)) and it works like a champ
Sebastian Andres
@sebandres
Mar 22 2017 23:14
ram-bot needs to warm up to me I guess :P
Ian Hofmann-Hicks
@evilsoft
Mar 22 2017 23:14
:trophy:
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:15
Is TS able to correctly determine the type of doSomethingWithValue?
Sebastian Andres
@sebandres
Mar 22 2017 23:15
maybe the typings are not 100% then, I'll have a look at that
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:15
Forgive me, I don't have TS experience
Sebastian Andres
@sebandres
Mar 22 2017 23:16
Yeah, it is able to get the final promise type correctly, is just that phantom parameter when the function does not need any
but all good, I don't want to pollute this with TS/typings issues!
thanks for the assistance :D
Piet Vandeput
@piet-v
Mar 22 2017 23:17
alrighty, finished my deepfilter, beware wall of text incoming
Brad Compton (he/him)
@Bradcomp
Mar 22 2017 23:17
:bowtie:
Piet Vandeput
@piet-v
Mar 22 2017 23:17
// words :: (string "a  b  c" => [a, b, c])
const words = R.pipe(R.split(' '), R.filter(R.identity));
// containsIgnoreCasing :: "a" => "b" => boolean
const containsIgnoreCasing = R.useWith(R.contains, [R.toUpper, R.toUpper]);
// getSubstringMatches :: ["a", "b"] => ["c", "d"] => length
const getSubstringMatches = R.pipe(R.intersectionWith(containsIgnoreCasing), R.length);
// leftUnionContains = ["a", "b"] => ["c", "d"] => boolean
const leftUnionContains = R.converge(R.equals, [getSubstringMatches, R.length]);
// valuesDeep :: [{a:"b"}, {c:"d"}] => ["a"] => ["d"]
const valuesDeep = (row, excludedKeys) => R.pipe(
  mapDeep((value, key) => excludedKeys.includes(key) ? '' : Object(value) === value ? R.values(value) : value),
  R.filter(R.identity),
)(row);
// filterDeep :: ["a", "c"] => ["b", "d"] => [{a:"b"}, {c:"d"}] => boolean
export const deepfilter = R.curryN(3, (excludedString = '', searchString = '', row = {}) => {
  if (!searchString) {
    return true;
  }

  const excludedKeys = words(excludedString);
  const searchValues = words(searchString);

  return leftUnionContains(searchValues, valuesDeep(row, excludedKeys));
});
Johnny Hauser
@m59peacemaker
Mar 22 2017 23:21
Any tips for this?
var mergeAllWith = curry((fn, objects) => reduce(mergeWith(fn), {})(objects))
var mergeAllWith = useWith(reduce(__, {}), [mergeWith, R.identity])