A really cool coding library I somehow overlooked - FSharpPlus
Every dev environment has things that drive you nuts. Usually it's little things, like having to look up something in the middle of doing something else. FSharpPlus helps fix that
The other day somebody on reddit asked the age-old question: why didn't F# have typeclasses or functors?
That's a long discussion, but while reading replies, somebody mentioned this cool litte F#+ library.
Over to GitHub we go!
Over the years, as I've written more and more solutions in F#, I've come across stuff I wanted to do where it seemed as if I were fighting the language too much. Stuff like common conversions with strings. Turns out a lot of other people have those issues also, so folks started collecting little goodies here and there. You're coding along, and suddenly you realize you want to make sure that string is all lower case. Wouldn't it be nice if there were a method to automatically do that, something like "foo".toLower()?
As most every coder knows, that's already don. It's in there. But it's not just that one little method. During regular coding you run across all kinds of stuff that hasn't been coded. Let's say you want to put hyphens in a string (why, I don't know)
// Extensions
let allCapsString = "I LIKE HYPHENS!"
printfn "Extensions to core types"
printfn "Original"
printfn "%s" allCapsString
let stickSomeHyphensInThere = String.intersperse '-'
printfn "Fixed"
printfn "%s" (stickSomeHyphensInThere allCapsString)
```
That's trivial stuff, but damn stuff like that gets old. And it's not just trivial stuff. Let's you've got a list and you're expecting only one element in it. Lots of business logic revolves around making sure you have one and only one thing. How about this?
let singletonTestData1=[1]
let singletonTestData2=[]
// reuturns the value or throws an error
let singletonRet1=List.exactlyOne singletonTestData1
// returns the value or none
let singletonRet2:Option<int>=
Option.protect List.exactlyOne singletonTestData2
That's pretty nifty because you can make sure it's only one item (or throw an error), catch the error and deal with it later (not shown here), or bail out on any decision-making entirely and let somebody else worry about it, ie, use an option.
I imagine we could do the same with atLeastOne. In fact, I might code that up as a PR. That's also a very common business requirement.
And you can extend generics too. How many times have you written a function and wanted to use it later as an operator? That kinda thing is fairly common in C++, and you can certainly do it in NET, but many times to get it done it seems unnecessarily complicated. How about this?
// turn any function into an operator
let smallerThan a b=a < b
// isSmaller = true
let isSmaller = 10 </smallerThan/> 20
```
I'm not crazy about that syntax, but fooling around with it some, I can see where the FSharpPlus guys were coming from. There are some odd language issues at stake, and this looks like a good compromise. I think this works better than some of the other options.
Once again, none of this is rocket science. All along you could have made this happen in whatever .NET language you use. It's nice having it already in there. Thanks guys!
I saw this one and almost had a nerdgasm. Every now and then you'll have a string and want to convert it to bytes, perhaps for some low-level fun with bits. Ever try to do that from scratch? Wow, it's a pain. There are excellent reasons it's a pain: there's encoding, there's collation rules, the list goes on and on. Human languages are tough. But what about just a dang default? Try this.
// Generic operators
// Whatever I've got, make it bytes
let myBufferBytes =
"This is something I need to do bit-level stuff with" |> toBytes
```
Because that's a type extension on a generic, that works with all types of stuff. Just throw whatever you've got to toBytes and move on.
You can do this on your own, but you'll kill precious development time (and focus) wading through docs. And if you only do it one or two times a year it'll be that same pain, over and over again.
// Need to splay out a bunch of processing and then sum when done?
let res42 = map ((+) 21) (async {return 21})
let myComputationallyHardAnswer = extract res42
Here we've wrapped up some common threading stuff along with collection traversal.
Of course, it's all composable with all of the other tools you have.
In another post I'll do some of the other cool stuff, like all of the mondad things they have, but that really gets into the technical part of coding itself instead of the convenience provided here. For now, you should check it out.
Comments ()