Closed Ne4to777 closed 2 years ago
I really don't understand
Fantasy Land specifies a simulation of type classes (an FP feature) in JavaScript. The closest it can get to functional type classes in a language which doesn't support them natively, is to specify classical interfaces (in text, not code, because JavaScript also doesn't have interfaces).
These classical interfaces are most easily and conveniently implemented in JavaScript via classical classes (using this
and stuff), but they don't have to be. There are various libraries out there which have values that conform to these Fantasy Land interfaces which were constructed without the use of new
or this
.
For example, Sanctuary uses Object.create
to create object structures like:
{
value: 42,
__proto__: {
isJust: true,
'fantasy-land/map': function(f){ return Just(f(this)) }
//...
}
}
So Sanctuary doesn't use classes or new
, but does use this
.
It's also possible to conform to the Fantasy Land interfaces without using any this
or new
:
const Identity = value => ({
value,
'fantasy-land/map': f => Identity(f(value)),
constructor: {
'fantasy-land/of': x => Identity(x)
}
})
So Fantasy Land does not inherently condone or condemn the use of such features, but having to simulate type classes through interfaces leads to a solution which naturally aligns well with the classical object oriented model. As a library author, you can choose to benefit from this alignment, but you don't have to. Finally, users of Fantasy Land compliant libraries don't typically notice either way: as a consumer of a FL-compliant lib you don't need to use any OOP features.
Well, even if all the developers of FP libraries write in OOP, why should other developers use FP? Therefore, the total defeat of the FP on all fronts is evident. The only thing that is widely used is composition. I've written a couple of examples, so what's the problem?
// of :: Applicative f => a -> f a
export const of = x => () => x
// extract :: Comonad w => w a ~> () -> a
export const extract = wa => wa()
// map :: Functor f => f a ~> (a -> b) -> f b
export const map = fa => g => of(g(extract(fa)))
// contramap :: Contravariant f => f a ~> (b -> a) -> f b
export const contramap = fa => g => of(x => extract(fa)(g(x)))
// ap :: Apply f => f a ~> f (a -> b) -> f b
export const ap = fa => fg => of(extract(fg)(extract(fa)))
// chain :: Chain m => m a ~> (a -> m b) -> m b
export const chain = ma => g => g(extract(ma))
// extend :: Extend w => w a ~> (w a -> b) -> w b
export const extend = wa => g => of(g(wa))
// compose :: Semigroupoid c => c i j ~> c j k -> c i k
export const compose = cij => cjk => of(x => extract(cjk)(extract(cij)(x)))
Well, even if all the developers of FP libraries write in OOP, why should other developers use FP?
Many people find the functions provided by Sanctuary and similar libraries quite natural:
> S.map (Math.sqrt) ([1, 4, 9])
[1, 2, 3]
> S.map (Math.sqrt) (S.Nothing)
Nothing
> S.map (Math.sqrt) (S.Just (64))
Just (8)
> S.map (Math.sqrt) (S.Left ('XXX'))
Left ('XXX')
> S.map (Math.sqrt) (S.Right (100))
Right (10)
> S.map (Math.sqrt) (S.Pair ('foo') (1024))
Pair ('foo') (32)
Someone using S.map
need not be concerned with its implementation.
Well, even if all the developers of FP libraries write in OOP, why should other developers use FP?
Many people find the functions provided by Sanctuary and similar libraries quite natural:
Someone using
S.map
need not be concerned with its implementation.
These are particular examples. And there really is nothing criminal about them. But can you show an exemplary FP program? So far, I only see terrible OOP-FP mutants.
I'm pleased that you do not find Haskell's fmap
function criminal. :stuck_out_tongue_winking_eye:
You may find concatFiles
and program
(and their surrounding code) interesting.
you held on well, but then something went wrong :) https://github.com/sanctuary-js/sanctuary-site/blob/ac68f7cbd1c541cfa653089b815cc4e1ae08b3b5/scripts/generate#L340
Аnd this is why "reduce" will always be a problem: https://github.com/sanctuary-js/sanctuary-site/blob/ac68f7cbd1c541cfa653089b815cc4e1ae08b3b5/scripts/generate#L568
Аnd this is why "reduce" will always be a problem
Why is that? It's not obvious to me.
Аnd this is why "reduce" will always be a problem
Why is that? It's not obvious to me.
the code inside was difficult to write through composition, so you wrote it imperatively. Therefore, the FP dies.
It's really unclear why you are contrasting the usage of objects with functional programming as if they were mutually exclusive.
It's really unclear why you are contrasting the usage of objects with functional programming as if they were mutually exclusive.
it's not just about objects, but about the context of objects. In js, there are three ways to pass variables into a function: arguments, global variables, and context. Functional programming is just arguments and nothing else.
Аnd this is why "reduce" will always be a problem
Why is that? It's not obvious to me.
the code inside was difficult to write through composition, so you wrote it imperatively. Therefore, the FP dies.
I am very confused about the flow of the conversation. For starter, ultimately, if you find some code unsatisfactory, you... fix the code and open a pull request?
Another thing is, I dont think "the code is in x style" is a good argument. people write code as an mean, not as an end.
"The code has error/is complex/inefficient/make reasoning hard because it screw up invariance“ is some of them, but "the code is written in imperative style" isnt really one IMO. (yes, mutable reference screw invariance and reasoning hard, but the code you object to is only using local variable). You can rewrite it with state monad or with recursion in general... but the code is "the same" - you only push the reasoning complexity inside the monad/the call stack.
And at the end of the line, "all code should be written using FP" is just a weird assumption. There are a plethora of domain out there, that can be written by one single person, but the SOTA isnt written in FP. Some example is chess engine, egraph, linear algebra, HPC. If fp die here, fp is dead everywhere.
Functional programming can use this
and new
. They don't break functions.
They may or may not be "OOP features" - whatever that means. Nobody cares.
Functional programming can use
this
andnew
. They don't break functions.
No, it can`t. Otherwise call it FOOP.
@Ne4to777:
Care to give the definitive definition of FP and OOP and then use them to explain why FP code cannot interact with OOP code?
Аnd this is why "reduce" will always be a problem
Why is that? It's not obvious to me.
the code inside was difficult to write through composition, so you wrote it imperatively. Therefore, the FP dies.
JS's poor recursion support means that many things cannot be written internally as cleanly as they might be in, say, Haskell. That doesn't mean they don't support an API that is FP.
@CrossEye , what do you mean by poor support?
@Ne4to777: Are you simply trolling here?
It's well-known that JS has low recursion stack limits. Last I knew (maybe 2019) most browsers were in the 10,000 - 20,000 call range, except that Safari went to 30,000. Moreover, although tail-call optimization has been specified since ES2015, almost all engines are ignoring this. So one cannot run recursive code against large data. And even against smaller data, the overhead is often performance-prohibitive. (For a case study, see Eweda, the predecessor to Ramda, which had elegant recursive code but couldn't perform.)
Recursion is a much cleaner way to write FP code; it can be done without variable reassignment, and often much more simply than its imperative alternatives. But since we cannot use it in JS unless we know the data is fairly small, we can't use it to build libraries.
@CrossEye , You said about browsers, but what does this have to do with javascript? Or then show me infinite recursion in Haskell in any browser.
We are discussing the concept, not the implementation. The scarcity of resources today should not kill the theory of tomorrow.
You put the question like this: why do we need to use JS because it is bad in FP? And I’m like this: since we are using JS in FP, then why we break the rules that we can not break?
@Ne4to777 You seem to be missing the fact that the fantasy-land interoperability specification is, despite the name, no pipe dream of tomorrow but rather a practical tool for today. If you want to discuss theoretical concepts, there are better venues than this issue tracker.
@bergus , that is, is it okay to use context in a contextless paradigm?
@Ne4to777:
We are discussing the concept, not the implementation. The scarcity of resources today should not kill the theory of tomorrow.
I have no idea what you're discussing. Most of us here are discussing a specification for data types with useful commonalities.
Moreover, a specification that cannot be implemented due to practical concerns is simply a work of fantasy.
PLONK
Hi! I really don't understand why programmers need OOP features in FP (like this, new and оthers). Looks like you don't believe in the FP paradigm and this specification is written for educational purposes only