
Show HN: Haskell library for pricing and information on crypto-currencies - aviaviavi
https://github.com/aviaviavi/cryptocompare
======
sfvisser
Haskell must be the only language for which I can skim a source file in under
60 seconds and almost fully grasp what's going on.

Bunch of datatypes, some instances, some helper code, some top-level IO code
tying everything upstream together. Done.

~~~
kccqzy
Then you’ve never seen tricky/advanced Haskell code that takes hours to grasp.

It’s not a language issue. In most sane languages you can write readable code.
And most languages also give you enough freedom to write unreadable code.

Here are some reasons why advanced Haskell code might not be readable if you
aren’t already experienced with this style of coding:

\- uses the C preprocessor extensively (usually to workaround API changes in
upstream libraries, but sometimes used for actual code generation, like in a
particular streaming library)

\- uses long TH declarations that give no insight into what they do (you only
know they have to return a `Q [Dec]` but it’s not obvious what, and dumping
splices only goes so far; it can even download things from the Internet to
generate code!)

\- uses advanced concepts like Church/Scott encodings of data types (though
with some comments this really shouldn’t be hard)

\- excessive type level meta programming

\- uses concepts like Bazaar, Bizarre, Conjoined, Strong, Yoneda, etc

By the way for some laughs you can read about how to write to write a
factorial program in Haskell from simple straightforward styles to convoluted
ones that use many advanced techniques:
[https://www.cs.utexas.edu/~cannata/cs345/Class%20Notes/10%20...](https://www.cs.utexas.edu/~cannata/cs345/Class%20Notes/10%20Haskell%20Programmer%20Evolution.html)
I hope no one actually writes production code like this but it does show you
how much of a steep learning curve could be needed before you understand
certain kinds of Haskell code.

~~~
SkyMarshal
True but Haskell's type declarations let you skip reading the actual
implementations. You can skim through the type declarations only and know what
it does, and that it won't compile if the implementations don't do exactly
what the type declarations do. Saves a few brain cycles.

~~~
aaron-lebo
This is turning a bunch of buts, but...that statement is true for any
statically typed language.

Fluency is underrated in general and is a big part of the disagreements over
languages. If you're really fluent in something, it's amazing how even
languages with flaws are less problematic than people think because once you
get used to idioms you learn to avoid those flaws and work in the context of
the language. I can skim over a JS file and have a similar experience of
understanding as the OP describes, given that JS is reasonable.

~~~
seagreen
> that statement is true for any statically typed language.

It's a spectrum!

The awesome part about Haskell is that you can assume functions are
deterministic and don't do IO unless they declare otherwise in the type
signature. This is really a huge deal. I like statically typed imperative
languages, but there's a big difference in expressiveness between a crude type
signature like `String -> String` and something more fine grained like `URL ->
IO ResponseBody`.

That said, Haskell has lots of downsides (many of which have been addressed in
the last few years, some of which have not) so it's not a perfect language by
any means. But it is very readable and refactorable.

------
mrkgnao
Clear, readable value-level Haskell is an underappreciated joy. What are you
using this for, if anything?

~~~
aviaviavi
Glad you liked it! I'm using this library to do my own analysis and
visualization of the value of different coins to inform my own investing. My
goal there is that some more tools will fall out of that endeavor, which I
would also release publicly. We'll see how that goes!

------
aviaviavi
Feedback is welcome! I wrote this library for my own use, but I'm happy to
hear any suggestions, code improvements, etc

~~~
endgame
* Consider using `Text` instead of `String`, as `String` is a linked-list of `Char` and quite inefficient

* Consider refining some of your fields into more constrained types. Sort orders probably only have a couple of valid values, and might reduce to an enumeration instead of `String`.

* In `instance ToQueryString PriceRequest`, I'd be surprised if those type annotations are necessary. The inferencer should be able to work out that `req` is a `PriceRequest`.

* In `instance FromJSON AggregatedSnapshot`, I think the `read`s should go. I think you want to use the `Float` instance of `FromJSON` instead. (What the `read <$> ...` is doing is parsing to a string, and then using the partial (!) `read` function on the result. JSON responses that have a value that fails to read for that key will crash the program.)

* In `instance FromJSON AggregatedSnapshot`, consider `withObject` here too, which encapsulates the pattern you're using.

~~~
thinkpad20
I don't have it in front of me but I would assume the FromJSON instance for
Float expects a JSON number, not a string. If the remote API makes the
(puzzling) decision to put numeric values in strings, then parsing those will
be necessary. Although, I agree that the 'read' function is the wrong one to
use here, due to it making the function partial (consider 'readMaybe'
instead?)

~~~
aviaviavi
It does indeed do that, there are numeric values returned as strings (i have
_no_ idea why they do that), which is why I had `read` in there.

I didnt know about readMaybe though, I'll definitely do that, thanks!

