These are chat archives for ramda/ramda

16th
Dec 2016
James Forbes
@JAForbes
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" http://staltz.com/is-your-javascript-function-actually-pure.html

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
@nlindley
Dec 16 2016 02:32
Are you thinking of this? http://queue.acm.org/detail.cfm?id=2611829
The Curse of the Excluded Middle
"Mostly functional" programming does not work.
Erik Meijer
Jonah
@jonahx
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
@JAForbes
Dec 16 2016 02:56
@nlindley yes perfect thank you!
btrepp
@btrepp
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.
Jonah
@jonahx
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
@JAForbes
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
@ongzhiliang
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'),
  funcA,
  funcB
)('param1', 'param2');

Is this possible to do in Ramda?

Bravi
@Bravilogy
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
@riston
Dec 16 2016 12:11
const a = { a: 1} if (code) { a.code = code }, any FP help for this pattern ? >D
Matt McKellar-Spence
@MattMS
Dec 16 2016 13:07
@riston you could start by wrapping that code in a function :stuck_out_tongue_winking_eye:
Aldwin Vlasblom
@Avaq
Dec 16 2016 14:29
@riston
  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
@mrtnbroder
Dec 16 2016 14:39
ramda folks!
can this function be shortened?
// initials :: Array String -> String
const initials = R.pipe(R.map(R.pipe(R.defaultTo(''), R.trim, R.head, R.toUpper)), R.join(''))
wonder if I can get rid of the R.pipe(R.map(R.pipe(
Jonah
@jonahx
Dec 16 2016 15:35
@mrtnbroder what about this?
@ram-bot
const name = ['jon', 'charles', 'reilly'];
pipe(map(head), join(' '), toUpper)(name)
ram-bot
@ram-bot
Dec 16 2016 15:36
'J C R'
Jonah
@jonahx
Dec 16 2016 15:40

If yoiu need to handle empty strings:

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

or

pipe(map(head), join(' '), toUpper, replace(/  /g, ' '))(name)
Brad Compton (he/him)
@Bradcomp
Dec 16 2016 20:32
@ongzhiliang Check out R.invoker for invoking your SomeClass.from method
R.invoker
Scott Santucci
@ScottFreeCode
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')?