With all the buzz of late, Functional Programming this and Composition that, terms like Functor and Monad may have crossed your feeds and left you ...
For further actions, you may consider blocking this person and/or reporting abuse
Well, first of all, welcome. It's nice to see more functional folks here.
I see it like this.
You write, you gather feedback, learn from your mistakes and then you write a better article.
As a novice in FP I would like to see things like: refactoring someone's imperative code.
I started writing my comment without reading the article. So I thought instead of putting it off for later I'll read it now.
At this point I've read up to this:
These posts assume an understanding of "currying", "partial application" and "function composition". If you feel a bit fuzzy on these topics, there are many resources available on the webs to get you sorted out.
I understand those concepts exactly (maybe not in JS, but certainly in Elm and Haskell. I guess I can transfer my knowledge to JS).
Let's continue reading.
But I also have to warn you that I've already read about monad on the futurelearn course about Haskell. But I can't tell that I understand the monad or that I can use it.
// data :: [ * ]
const data = [
{ id: '9CYolEKK', learner: 'Molly' },
null,
{ id: 'gbdCC8Ui', learner: 'Thomas' },
undefined,
{ id: '1AceDkK_', learner: 'Lisa' },
{ id: 3, learner: 'Chad' },
{ gid: 11232, learner: 'Mitch' },
]
Why do you have null and undefined here?
Here's where I'm getting lost.
Our examples will be defined with the following list of requirements:
My questions are:
Why such requirements.
Continuing.
At this point I briefly looked at Crocks.
And now I started retyping:
is gid purposeful or a typo?
And why you have some ids like numbers, a single number, or a mix of letters and numbers? Because data like this doesn't make sense to me. Is this how JS world looks like?
At this point I went to bed to lie down. I contemplated and when I returned I deced to look you up on twitter. Didn't find one.
Looked at your Github though.
You are the creator of Crocks!
Interesting.
At this point I'm watching your youtube video "pointfree and combinators".
Comb (ai) nators - is really a weard way to pronounce that word.
At this point I jumped around the article.
I have this to say:
I didn't think that functional JS would be that weird.
But I also understood that the purpose was to clean the data. I would actually start the article with that. Like we have some unclean data and we are going to clean that up.
You have actually demonstrated that but in the middle of the article. The question is? Would it be better to start the article with that? In my opinion it would.
I'm used to challenges on Codewars. It's such a good thing that they provide input and outputs. It's the first place where I look.
P.S. I rethought my earlier statement that functional JS is weird. It's actually not that weird.
Wow that is some amazing feedback. Thank you for taking the time for putting it all down. I cannot tell if your question are meant to be rhetorical, but I will err on the side of they are not and try to address them.
In my experience with the web or working in dynamic languages, the data you receive may come from multiple sources and/or not ideally normalized for proper processing. I found data like I presented above in things like service oriented architectures and even when compiling scientific data from different instrument sources (even worse for double blind studies or peer review aggregation). So while fp concepts in JS is easily explained with simple curried
add
functions onNumber
, I wanted to provide a case a bit closer to real life.Same answer as above.
A lot of this function is to normalize the input and separate the valid data points from the noise.
@evilsoft on twitter
Nice, just one of the effects of reading about them in textbooks without a professor to say the word out loud I guess.
It is not that Functional JS is weird, it is that working in a dynamic language presents some unique challenges that Haskell and Elm (and a few others) do not have to encounter.
This is where I think I may not have been clear on the intent. This is supposed to start down our path of understanding how to use ADTs in our functional JavaScript. I wanted to start by contrasting how different typical imperative JavaScript looks compared to the same functionality implemented code with ADTs in JavaScript. It seems that you were fixated on the MacGuffin that was used to drive the "plot" and be the actual focal point itself (other then to provide the contrast). So this seems to be where the failure in communication on my part lies.
I take every bit of criticism, good or bad to :heart: and use to improve my material in my video, live code and egghead lessons. So I appreciate you taking the time and passion to make sure the the content I provide is getting the message across.
I am going to make some tweaks to this posting to address a couple of the things you pointed out. And will defiantly keep some of these points in mind while I edit the other 7 posts in this series.
Thank You Again For Taking The Time,
evil.
EDIT: One thing I forgot to mention, for things like do not throw and just return an empty
Object
and things like that. When working in dynamic languages we tend to use a concept of Reasonable Defaults. So instead of just erroring out if life is not what we expect to be, we can signal that all is not well by returning an emptyObject
(in this case anyway) as anything that relies on this program would get theObject
it needs with the information that there is nothing to process.I was writing the comment while I was reading. Because I wanted to show you my thought process "in real time". If I were recording a screencast you would have heard me asking this question.
This way I can show where the friction occurs better.
Oh sorry about that.
Thanks so much for doing this, I find feedback like this very helpful!
Also did you happen to do any of the exercises? I am curious how they aided/hindered your understanding.
To be honest, I haven't.
The reason is... actually, it doesn't matter what the reason is.
I will do what I'm supposed to do.
I will finish what I started.
Now I will write my comment again in the same style. I have attached my gedit window with the above all other windows option. I will reread the article especially the functional part (because some of the functions I don't understand). I will narrate as I go along. I will call this "narration style".
I have to say that I'm not that proficient in JS. So correct me if I'm wrong. What I think I see here is destructuring. Pattern matching in other words. But on the right side there is a library so I don't really see how that works. I think I'll go right now and watch something on youtube to understand that part. I'll be as thorough as possible.
I opened youtube and searched es6 destructuring. I see a lot of videos. I'm going with the fun fun function video. If necessary I will narrate my process.
Here's an example:
let animal =
{ species: 'dog'
, weight: 23
, sound: 'woof'
}
// the destructuring
let { species, sound } = animal
// and from this I understand that the order doesn't matter.
Well, that's actually all I need at the moment. If order doesn't matter I can take out any function out of the library.
That's it. The video is 10 minutes long, I stopped at 1:27. Back to the tutorial.
At this moment I'm reading the requirements to really get them.
This part, was a bit hard to understand. Because of the use of the "double negative". I understand that it's not. But you can simplify it.
I'd go with:
When the data is an Array with at least one acceptable record, an empty Object will be returned.
Tell me if I've "refactored" your requirement correctly.
Oh, I'm looking the type signature:
// data :: [ * ]
the "*" is not a type variable. But a wildcard. It kinda expects something unpredictable inside an array.
You know I also look at this:
From these requirements, we can implement an imperative function that does the following:
Using a third-party library called crocks for some doing our type validation, we can provide an implementation like this:
And think that this could be written as comments in the code.
And that would be may be better, or not. Is there a way to find out?
At this point, I remembered that your purpose was to talk about ADT and monad. I went to the beginning of the article.
I'm not familiar with the word embelishment. I'm looking it up.
Embelishment is a decorative detail (elaboration, or addition).
I opened my editor to retype the example. I'm going back and forth between retyping and reading
I do it slowly so I understand everything thoroughly. I'm going back and forth. I read one implementation, then retype and think. Then I read another one, and then retype again.
Oh, now I've noticed you don't have semicolons in the code. That's good.
I need to download the 'crocks' library. To run the examples. I`ve just installed crocks.
npm install crocks -S
It says "All you need to do is run the following to save it as a dependency in your current project folder".
How do I save it as a dependancy? What is -S by the way?
Okay, I've got the imperative code well, I think. Now, to the functional part. Now, I think I should the functional part in a separate file. Or not?
Gosh, it's 1:43 in the morning. I'm getting so sleepy. I will continue tomorrow when I wake up.
Alright, I have woken up.
I want to make sure that I get the function composition in JS.
In Haskell we do it like this.
func1 . func2 . func3 x x
So in JS that would be
composeK(func1(Int), composeK(func2(Int), func3(Int, Int)))
This is hypothetical, but I think I get it right.
What I see that I don't understand is Maybe.of. After that I looked at the converge function. It takes a lot of functions as arguments. Right now I'm looking at the documentation on converge. The reason I'm diving deep is because I want to do the exercises.
Now I see this. I doesn't take all the arguments, so to speak. So there is partial application at play. Maybe.of takes data as an argument and then it all reduces to one value.
At this point I haven't scroll down, but I remember you have given some explanations below. Now it's time to read them.
The function Safe led me to Maybe in the library. I'm scrolling and see chain there as well. I looked at both don't really understand them.
Let's continue anyway.
So, I see the reference to the fluent api. Which doesn't tell me anything, I tried understand it, but decided that is just too much.
Conclusion: the reference to the fluent api is completely unnecessary and will create more confusion.
Now I will go through the exercises.
If the reduce works with numbers and these numbers will be reduced to a singe value I understand.
But when the reduce (or fold in my practice) works with different data types other than numbers I have problems.
Okay, I just thought it about.
Here we have an empty array as an accumulator, and we will push object that are satisfy a predicate.
Now should I write this predicate as a helper function?
Here's my little refactor:
`js
let result = records.reduce(filter_records(records), [])
const filter_records = records => {
return isObject(records) && isString(records.id)
}
`
I think it's not correct.
Will this work?
`js
let result = records.reduce(filter_records(sum, records), [])
const filter_records = (sum, records) => {
return sum + (isObject(records) && isString(records.id))
}
`
I unfortunately, cannot find out at the moment. Because, I have no idea of how to connect Crocks. It is installed, I've never used package.json, I've not used any build tools yet.
Here, I need some help.
2 - 5. I feel that lack of knowledge of JS is a little hindrance and that every time I do something I need to dig deeper. I wouldn't say I'm lazy. But in this particular instance I am. Maybe I will return at some point and do the exercises. I liked the "reduce" exercise.
Why did I wrote all those comments?
So good.
So there are a couple things you've shown me I need to do. First of I need to update:
To read more like:
Also good call on the needing of
crocks
for the POJ example. I need to break those out into functions like:Yeah people should not have to install crocks at this stage in the game.
How about
Arrays in JS can be of mixed type, so we typically denote that with
[ * ]
, as opposed to something like[ a ]
where we expect everything to be thata
. Well when our functions can work with mixed typedArray
s. In reality we want to strive for[ a ]
or even better something like[ Number ]
, but sometimes at the edge, we need the[ * ]
You got mostly the compose bits down, except you would just use
compose
,composeK
is for Kleisli arrows ( basically>=>
or fish in Haskell). Also you can use eithercompose
orcomposeK
like this:So this is more than just a filter, we are change types. we move from an
Array
to anObject
. So we want to reduce with{}
as our empty on the fold, then only add valid records keyed by their validid
to the accumulator. Does that make sense?Also just to help a fellow Haskeller out here is a quick JS -> Haskell key:
compose
->.
(butcompose
is n-Ary)composeK
->>=>
(butcomposeK
is n-Ary)[type].of
->pure
for Applicative Functor /return
for Monad[instance].chain
->bind
liftA2
->liftA2
converge
-> S' or Phoenix Combinator.I mostly don't know about them. So you are telling me new stuff that I should learn : ))) That's great. Thanks.
Do you think the concept "having the end mind" is applicable here?
and
So, basically you first show this at the start of the article (introduce the end goal):
And then you just show the imperative approach and then show how to refactor that approach into the functional one and what are the benefits.
Great article. Though I think someone unfamiliar with functional programming will get lost around the code block where you introduce:
Assign, Maybe, composeK, converge, isArray,
.isObject, isString, liftA2, mreduceMap, objOf,
prop, safe
There is a lot to digest in there. If you don't already have an understanding of every one of those functions, you risk losing the reader.
It could be helpful to have a step before this to explain these concepts. I think if someone already understands these, they will also already know what a
Monad
is too.Cheers!
Thanks so much for the feedback.
The intent for that is not to understand it, but compare how things look differently. Personally I like to show the end goal, at a glance. It is my hope by the end of this series they will be able to understand it.
Maybe I could lead with the paragraph saying it is okay to not understand this, just look at the style. Thoughts?
I guess it depends on who your target audience is. There are a lot of functions a non FPer has never been exposed to.
Reading your article taught me an important lesson:
I was reading your article in a linear fashion from to top to bottom. Instead of expecting the author to write in a style that I want. I can actually skim articles first and look for the inputs and outputs.
And then proceed to read the article in a linear fashion. This way I will have the bigger picture in mind and less friction when I start diving in.