These are chat archives for ramda/ramda

Dec 2016
James Forbes
Dec 16 2016 00:09

@Bravilogy depending on your definition of functional programming, you could say they both are, neither are or the top isn't and the bottom is

When we say "functional programming", we could be talking about purity, we could be talking about composition (which is what I think Brian Beckman meant when he was saying "functional programming is programming with functions")

If we decide functional programming is about purity, does that exclude side affects within a visitor function, or are we only interested in referential transparency, that whatever args go in yield the same result every time? They sound the same, but purity is a continuum.

The first example is using a Promise, so its eager, and most would say its impure because it can return a different result every time you call getCompanyNames. But I think its a valid argument that function will return a Promise Array Userevery time, and perhaps the results might change, or it might get an network error, but that behaviour is encoded in the type, and the types always line up, so one could still say its referentially transparent.

The 2nd function seems like its obviously functional. But @staltz wrote a great article arguing that in JS nothing is ever "pure"

I personally value referential transparency, and purity, laziness etc, but I value composition the most. So when I think and talk about functional programming, I'm optimizing for composition first. But its too broad of an umbrella. Clojure's FP has a different flavour to say Haskell's, and I think that's a good thing.

So as I said, you could say they both are, neither are, or only the bottom is depending on your viewpoint/definition.

There was another article doing the rounds saying FP has no value unless you go all in. Maybe someone can remember the source / link. And that's another valid perspective (which I don't agree with).
Nicholas Lindley
Dec 16 2016 02:32
Are you thinking of this?
The Curse of the Excluded Middle
"Mostly functional" programming does not work.
Erik Meijer
Dec 16 2016 02:49
@Bravilogy While @JAForbes gave a more complete answer, I’d say that as a practical matter, it’s a decent example for demonstration. I noticed at a glance a small improvement you can make
const propContains = (key, needle) =>
    pipe(prop(key), contains(needle))
James Forbes
Dec 16 2016 02:56
@nlindley yes perfect thank you!
Dec 16 2016 02:58
Is there any prism support for ramda?. Normal lenses throw undefined exceptions when composed (which makes total sense), and I can't seem to find any prism examples. I gather I would need to have the Maybe type from ramda-fantasy, and I am 110% cool with that.
Dec 16 2016 03:02
@Bravilogy I’d also consider avoiding unnecessary intermediate variables, and using the ramda versions for everything, allowing you to go point-free. Eg:
const filteredUsers = pipe(
  filter(pipe(prop('website'), contains('info'))),
  map(path(['company', 'name']))
which, barring the pipe in there, almost reads like a sentence
James Forbes
Dec 16 2016 03:08

I wrote that post after just waking up @Bravilogy, sorry, reading it now its a bit scattered :D

I forgot to say, using a for loop seems like its not functional becauses its mutating i, and we're manually telling the computer how to iterate, so its imperative. But that's when you can argue about whether or not internal purity matters, because if the function always returns the same output given the same input it doesn't matter that there was a for loop.

I'd argue a large part of FP is the ability to ignore the implementation and only care about composition of types. So by that reasoning it seems pretty unimportant if the function body used loops as long as it obeys a contract of purity.

FP can sometimes seem like a doctrine, or a dogma, where using certain approaches is morally superior or inferior! We use terms like "impure functions" which sounds like a medieval value judgement. But I've found most can agree that there are many flavours of FP and many contexts where it can be applied and different contexts have different strengths/weaknesses.

BUT I agree with Erik Meijer's at least in the sense that the difference between 100% purity and 99% purity is vast.

Zhiliang Ong
Dec 16 2016 08:34

Hello. I'm trying to do something like

let x = funcA(funcB('param1', 'param2'));
x = SomeClass.from('param1' ,'some_constant_value');

This is what I came up with, which threw some_constant_value is not a function

const  x = R.compose(
  SomeClass.from(R.__, 'some_constant_value'),
)('param1', 'param2');

Is this possible to do in Ramda?

Dec 16 2016 10:06
@JAForbes @jonahx thanks guys, very helpful! And especially thanks @JAForbes for such a detailed explanations / arguments :) I have read that post by @staltz yes :+1:
Risto Novik
Dec 16 2016 12:11
const a = { a: 1} if (code) { a.code = code }, any FP help for this pattern ? >D
Matt McKellar-Spence
Dec 16 2016 13:07
@riston you could start by wrapping that code in a function :stuck_out_tongue_winking_eye:
Aldwin Vlasblom
Dec 16 2016 14:29
  1. We prefer to use expressions over statements, so: a.code = code || undefined (instead of if(...){...})
  2. We prefer not to mutate stuff, so: const aa = R.merge(a, {code: code || undefined})
  3. We prefer not to have to assign variables intermediately, so: return {a: 1, code: code || undefined}
Martin Broder
Dec 16 2016 14:39
ramda folks!
can this function be shortened?
// initials :: Array String -> String
const initials = R.pipe(''), R.trim, R.head, R.toUpper)), R.join(''))
wonder if I can get rid of the R.pipe(
Dec 16 2016 15:35
@mrtnbroder what about this?
const name = ['jon', 'charles', 'reilly'];
pipe(map(head), join(' '), toUpper)(name)
Dec 16 2016 15:36
'J C R'
Dec 16 2016 15:40

If yoiu need to handle empty strings:

pipe(reject(equals('')), map(head), join(' '), toUpper)(name)


pipe(map(head), join(' '), toUpper, replace(/  /g, ' '))(name)
Brad Compton (he/him)
Dec 16 2016 20:32
@ongzhiliang Check out R.invoker for invoking your SomeClass.from method
Scott Santucci
Dec 16 2016 23:04
replace(/ /g, ' ') won't properly handle more than one empty string in a row (since /g only acts on multiple matches in the original text and does not match the replaced text), nor (an) empty string(s) as the first or last entry; maybe replace(/^ +| +$|( ) +/g, '$1')?