
Haskell In New Clothes - culturedsystems
https://github.com/serras/hinc
======
curryhoward
I love seeing new Haskell projects, though I personally would rather just
stick with Haskell's clean syntax:

    
    
      data Maybe a = Nothing | Just a
    

...over this:

    
    
      data Maybe<a> {
        Nothing,
        Just(value: a)
      }
    

I understand that programmers coming from mainstream languages might feel
uncomfortable without all those angle brackets, curly braces, and parentheses
(why do C-like languages have so many ways to syntactically group things?), so
if this project helps them ease their way into Haskell I totally support it.
However, a small part of the joy of Haskell is freeing yourself from the
arbitrary syntactic boilerplate that most languages have.

~~~
dmitriid
> freeing yourself from the arbitrary syntactic boilerplate that most
> languages have.

And coming up against arbitrary three-four-character combinations people come
up with for their operators.

Terser does not automatically mean better (or J and K would've won that
argument a long time ago).

At least mainstream languages are usually _consistent_. A method call is a
method call. A structure is a structure. What is this ungodly mess?

    
    
        type API = "polls"                                           :> Get  '[JSON] [Poll]
              :<|> "polls" :> Capture "question_id" Int              :> Get  '[JSON]  Poll
              :<|> "polls" :> Capture "question_id" Int :> "results" :> Get  '[JSON]  PollResults

~~~
mrkeen
> What is this ungodly mess?
    
    
        type API = "polls"                                           :> Get  '[JSON] [Poll]
              :<|> "polls" :> Capture "question_id" Int              :> Get  '[JSON]  Poll
              :<|> "polls" :> Capture "question_id" Int :> "results" :> Get  '[JSON]  PollResults
    

Delightful :D

    
    
      The API is the route "/polls" accessed via GET, returning a list of Polls in JSON format
              or the route "/polls/question_id" where question_id is an Int, accessed via GET, returning a Poll in JSON format
              or the route "/polls/question_id/results" where question_id is an Int, accessed via GET, returning PollResults in JSON format

~~~
runeks
Since we’re discussing syntax I’d like to question the necessity of the tick
preceding [JSON].

Could we leave out this tick given that the kind of this parameter is [*]?

~~~
pyrale
For reasons that are not easy to explain, no.

[JSON] and '[JSON] have different meanings. Here, '[JSON] does not refer to a
list of json files, but to a type-level list of the mimetypes that can be
returned. You could see '[JSON, PNG] instead, which would make no sense in the
context of a list type declaration.

The genius of Servant is that the DSL doesn't require you to know how '[] is
implemented and why it's different from [], you just have to know the DSL.

------
nervous_north
I personally prefer Haskell's syntax. I find myself using JavaScript
transpilers like BuckleScript to take me into a typesafe land with ML syntax
rather than using a language like TypeScript with Java like syntax.

That said, I really appreciate seeing work like this. Haskell is super
powerful and it's great to see transpilers like this that are lowering the bar
of entry to Haskell to those more familiar with the traditional languages.
Nice job!

------
_alex_
I dont think a lack of curly braces is whats keeping haskell from taking off.
It’s the “I need to go study category theory to be able to read the docs on
any useful package” problem and the proliferation of language extensions.
Taking some of the ivory tower out of the learning curve will do a lot more
than adding some tokens.

------
japanoise
Contrary to the other commenters, I see this as a huge improvement. Maybe I'm
more used to languages like C rather than what, ml, python, pascal?

------
spankalee
Whoa, this is amazing! I find this example much, much easier to read:

> For example, where Haskellers would write:
    
    
        f = average . filter (> 0) . map normalize
    

> in hinc the idiomatic translation would be:
    
    
        let f(lst) = lst.map(normalize)
                        .filter((x) => x > 0)
                        .average
    

These seems like very sane, pragmatic choices considering the massive segment
of programmers used to C/Java/JavaScript derived syntax.

Now, if the currently top comment about category theory could be addressed, I
think we'd have something.

------
rattray
The thing that's always turned me off Haskell is language extensions and the
associated fractal fracture of the language. Sorry, I don't want to learn a
dozen different styles of a language.

PureScript always seemed a little more appealing from that perspective, but
doesn't seem to have really caught on (eg;
[https://trends.google.com/trends/explore?date=today%205-y&ge...](https://trends.google.com/trends/explore?date=today%205-y&geo=US&q=purescript))

~~~
Vosporos
Sorry, could you provide an example of those different styles?

~~~
tome
To reply to both of your respondents at once,

> Of course, each language extension changes the syntax and/or semantics of
> the language, so in order to "learn Haskell" I'd have to learn one or more
> flavors/styles of it – and there doesn't seem to be one standard set of
> language extensions that are commonly used

> It seems like every Haskell project makes use of a different subset of 10 to
> 20 language extensions, each of which requires some deep knowledge of type
> theory to understand how it affects the language.

These comments are both pretty off the mark. It's unhelpful to think of
language extensions (the most commonly-used ones at least) as _extending_ the
language. It's more that there is one overall Haskell language and the
_absence_ of a particular language extension _disables_ a particular feature.
The language is, by and large, _more_ coherent with language extensions turned
on, not less coherent.

~~~
elbear
Maybe it's more coherent, but the fact that, after learning the language, you
discover that you have 20 more extensions to learn feels like a never-ending
quest. I think that's what the previous commentators mean.

If the language is more coherent with the extensions, they should enable them
by default.

~~~
pyrale
Most haskell programmers I know don't know or use all extensions, and do just
fine without them.

I personally don't know most of them, and I've been doing haskell
professionally for years now. Once in a while, I will need to do a specific
thing and will google up stuff, and the thing I'll write will remain contained
in a couple files, and callers won't have to know about it.

It is absolutely _not_ a prerequisite to know all extensions to earn one's
living doing Haskell, just like one doesn't have to know the JVM or the dozens
of design patterns inside and out to program in Java.

~~~
rattray
> It is absolutely not a prerequisite to know all extensions

Which ones are a prerequisite? OverloadedStrings? TemplateHaskell? How many
others?

If the answers to that list were enabled by default in the language, and most
Haskellers agreed on them, there really wouldn't be much complaint – you'd
reach for these fancy macros when you need them, like you say, and that'd be
that. A newcomer wouldn't know that some of them are required reading and
others aren't and not know which is which.

~~~
pyrale
I have never touched template haskell.

OverloadedStrings is one of the few extensions you'll see everywhere, but
there's nothing to remember about it. It's really the kind of thing you'll
understand in 10s and find obvious forever after.

> If the answers to that list were enabled by default in the language, and
> most Haskellers agreed on them, there really wouldn't be much complaint

Here is the thing: just moving all the extensions into the language and
removing the pragma would basically mean there would still be the same amount
of things in the language, but with no convenient way to know what's used in a
specific file, and it would be hard to research that topic which you don't
know.

Extensions are great in that they force devs to label files with searchable
names for the concepts they use in the code.

> A newcomer wouldn't know that some of them are required reading and others
> aren't and not know which is which.

A newcomer, just like a seasoned haskeller, shouldn't bother learning new
extensions if they're not about to use them. That's the way to go forward.

------
rishav_sharan
As far as functional languages go, F# (and thus OCaml which is the parent
language of F#) IMO has the best syntax. The code is actually readable even if
you haven't ever written a functional program and everything feels super
practical about it.

Its a shame that F# doesnt gets the attention it deserves.

------
quotemstr
I want to like Haskell, but I think lazy evaluation is fundamentally broken.
Haskell's facility for optional strict evaluation doesn't really repair the
fundamental defect, which leads to memory leaks and unpredictable performance.
And certain magic functions are strict anyway, and you just have to know what
those are. I just don't see making lazy sequences easy as being worth the cost
of making lazy evaluation the syntactic default.

Given that Haskell is fundamentally and irreparably broken (IMHO) in this way,
it seems like a waste to devote effort to it instead of better functional
languages like ML.

~~~
pyrale
May I ask you what kind of "magic" functions you have in mind ?

~~~
quotemstr
&& is always strict in its first argument. Pattern matching is strict. It's
hard to predict when some random function you call with force a thunk you've
passed it. My position is still that lazy-by-default is a really bad
evaluation policy and that consequently, Haskell is a dead end in language
evolution.

~~~
pyrale
> && is always strict in its first argument.

Well, if you need to evaluate (&&) you will necessarily need to evaluate its
first argument. Much like (||). This behaviour works similar in many other
languages.

On the other hand, the first argument passed to (&&) will never be evaluated
until needed, so it is still lazy as expected. A good way to test this
behaviour is to try this in GHCI:

    
    
        let a = (length [1..] == 3) && False
    

Simply declaring a won't enter in an endless loop, but asking to show a will
indeed loop endlessly.

Likewise, it is hard to understand how you expect pattern matching to not look
at an expression's value when deciding which branch of the code it should use
next.

> My position is still that lazy-by-default is a really bad evaluation policy
> and that consequently, Haskell is a dead end in language evolution.

Yeah, I have understood that you have an opinion. Nevermind that people run it
in production without issues.

~~~
quotemstr
People run Java in production without issues, but we know today that languages
shouldn't have nullable-by-default pointers. Software is infinitely malleable:
that you can make something work is no argument that it's the right thing.

~~~
pyrale
People rarely call Java a dead end, or irreparably broken, though.

------
logicchains
To me the biggest advantage of this that it's not whitespace sensitive, which
makes it way easier to refactor and automatically indent/format code. Although
I'd have preferred something more ML-like.

~~~
dmytrish
It's possible to write regular Haskell with semicolons and curly braces.
White-space sensitivity is just a syntax sugar for that [1].

> easier to refactor and automatically indent/format code.

What are the advantages of white-space insensitive code for refactoring and
formatting?

[1]
[https://en.wikipedia.org/wiki/Haskell_features#Layout](https://en.wikipedia.org/wiki/Haskell_features#Layout)

~~~
logicchains
With white-space insensitive code I can easily cut/paste code from one
function to another, without having to potentially manually re-indent it
afterwards. This makes refactoring easier.

For formatting, it means I never need to manually add any spaces or tabs: the
formatter always knows exactly how to indent it. With whitespace-sensitive
code, I have to manually pick the indentation, as different indentations could
have different semantics. That's why if I hit tab in Emacs when editing a
Haskell file, it will cycle through multiple possible indentions. If I hit it
in a whitespace-insensitive language, it will just move it to the "correct"
indentation straight away and I don't need to worry about it.

Using {} braces in Haskell seems less intuitive, at least to me. E.g. how
would I use braces to avoid the need to manually indent a nested where
statement?

~~~
gnufx
I have to fix up the layout essentially manually every time I have to edit C
in someone else's idea of correct layout when they haven't included C Mode
rules for it. (That's assuming they want a consistent style for changes, of
course.)

If simplicity of parsing, and cut-and-paste are important, we should be using
Lisp, of course, but there are still different indentation styles.

------
hsavit1
As a Typescript developer, I really like this! Haskell has always been
difficult for me to grok but this syntax makes bridging the gap really
intuitive. Bravo!

------
namelosw
It's a great attempt, just like ReasonML.

Maybe the 'data' could be called 'enum'? I believe Rust/Swift ADT definition
use keyword 'enum' and it might make it more familiar to the mainstream.

While the 'await' is pretty recognizable, the word itself seems to be too
coupled with asynchronous operation too much.

------
dunefox
This looks so noisy compared to normal Haskell syntax.

~~~
scotty79
I'd call it verbose. In comparison Haskell syntax seems like a lot of meaning
should be magically assumed by default. Sort of like mathematicians tend to do
in their notation. Here it's spelled out.

Like in the example of

    
    
        f = average . filter (> 0) . map normalize
    
    

vs

    
    
        let f(lst) = lst.map(normalize)
                    .filter((x) => x > 0)
                    .average
    

In the second version I can clearly see that I'm creating a function that is
supposed to take one argument. It even has a name that might indicate what I'm
expecting.

Don't get me wrong. All the required information is there but some of it is
"written between the lines".

Sort of like CoffeeScript which people tend to hate (and I love, just because
I understand JS perfectly and in comparison to CoffeeScript it looks noisy for
me).

~~~
johnday
Standard, base Haskell admits the following definition:

    
    
      let f lst = lst 
                  & map normalize
                  & filter (\x -> x > 0)
                  & average
    

Which is barely different from your second presentation. (EDIT: just in case
you think I'm ass-pulling here, this is fairly idiomatic code that I'd
certainly write in prod! See another comment I posted earlier this week...)

~~~
gavinray
I have almost no Haskell experience, but I was playing around in GHCI the
other day and it seems you can add parens to function arguments if you want?

Nobody seems to add parens to separate arguments from function calls though in
Haskell, never seen it but it works.

    
    
      let f(lst) = lst 
                    & map normalize
                    & filter (\x -> x > 0)
                    & average
    
      Prelude Data.Function> let f(lst) = lst & map (\x -> x + 2) & filter (\x -> x > 4)
      Prelude Data.Function> f([2,3,4])
      [5,6]

~~~
marcosdumay
> you can add parens to function arguments if you want?

Of course. This "(x)" and this "x" are the same. You can put any expression
inside parenthesis. Haskell also has tuples, that you write as "(a, b, c)" and
can use as a function parameter.

There is even some functions in base for converting functions that receive a
tuple into functions that receive many parameters and the other way around.

~~~
gavinray
It seems kind of weird coming from other languages to not visually distinguish
the function call from the arguments if you have the option.

Nobody in Haskell does this (to the point I had no idea it could be done until
I tried it) so clearly it's something you get used to, but boy does it look
real alien to me.

~~~
marcosdumay
Space is the symbol that denotes a function call in Haskell.

It is indeed different from other languages, that require an argument list in
parenthesis. It can be different because values and functions are not
ambiguous on Haskell; there isn't such thing as a function with no argument.

------
k_bx
I think there’s a good use case for such a thing: make it as compatible with
current Rust syntax as possible, including keyword names. This way you’d make
use of people’s familiarity with Rust, and give them “lookalike Lang with
better types and a GC”.

------
IshKebab
Honestly the syntax of Haskell is unnecessarily weird and I think this project
is proof that it doesn't have to be. Haskell's syntax has really put me off
learning it. I'd even say some parts of the syntax are elitist - they are
almost deliberately - and unnecessarily! - hard for beginners but great if you
are a language nerd and understand currying, lambda calculus and so on.

This is way better, but to be honest I don't think I'll use it because the
extra easiness of learning with a sane syntax is probably going to be not
worth the extra hassle caused by not learning the syntax that everyone else
uses.

Still, great job! Now do the git CLI. :-)

------
hyperpallium2
C-like [http://james-iry.blogspot.com/2009/05/brief-incomplete-
and-m...](http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-
wrong.html?m=1)

------
brudgers
companion site,
[https://serras.github.io/hinc/](https://serras.github.io/hinc/)

------
li4ick
I mean...why not just go full OCaml at this point?

------
javcasas
Without OO as main paradigm, and without being shoehorned into the JVM,
Haskell has no chance to be mainstream. Stop trying to make it mainstream, it
will only remove from Haskell what makes Haskell great.

------
gnufx
How do people who are thrown by juxtaposition as function application and
point-free style cope with Unix shell pipelines?

------
dreamcompiler
Improving Haskell with Javascript syntax is like improving a Mark Rothko
painting by sprinkling glitter all over it.

~~~
scotty79
It's more inspired by TypeScript I'd say and there are also features inspired
by Rust.

I'd call it readable haskell not hinc.

Most popular languages created sort of universal visual language of what
things mean when they look certain way and weird languages with very cool
mechanics like Haskell, have much trouble with conveying this mechanic to the
new user when they don't subscribe to this visual language (for historical or
whatever reasons).

~~~
pyrale
> Most popular languages created sort of universal visual language of what
> things mean when they look certain way

python kind of ignored this "universal visual language", and the language
seems pretty popular with newcomers.

~~~
scotty79
Not really. Python has exactly the same structure as all other popular
languages. Lack of brackets doesn't make it much different.

Ruby is weirder.

------
amelius
Huh, this is like saying "who needs parsers?" Well, they've been invented for
a reason. So after the NoSQL movement, we now have NoParser. I fear we might
end up back at assembly or even microcode. Sure it will make life simpler, but
it's the wrong kind of simple.

------
agumonkey
oh god, no top level patterns

it's such a beautiful thing ..

~~~
sullyj3
I really like the Unison syntax:

    
    
      fib = cases
        0 -> 0
        1 -> 1
        n -> fib (drop n 1) + fib (drop n 2)
    

(drop is (-) for natural numbers, clamping to 0.)

~~~
johnday
The fairly popular `LambdaCase` extension gives

    
    
      fib = \case
        0 -> 0
        [...]

------
platz
well, it's cute trick - not sure what the utility is.

------
wseymour
I'm looking forward to playing with this.

Coming from a C-style language background, I've always found the syntax of
languages such as Haskell and ML to be alien, to the point that I can't get my
head into learning one of them, despite their obvious power and utility.

I've been looking for some kind of C-style dialect for one of these languages
for a long time, so thank you very much for creating this.

At the risk of hijacking this thread; is anyone here aware of other projects
for Haskell or other languages that achieve a similar goal?

~~~
smabie
ReasonML is similar. What do you find confusing about the syntax? Imo,
Haskell/ML syntax is more readable and lightweight than traditional C-style
syntax.

