10 ms·
Haskell In New Clothes
- brudgers 6y agocompanion site, https://serras.github.io/hinc/ https://serras.github.io/hinc/
- hsavit1 6y agoAs 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!
- dunefox 6y agoThis looks so noisy compared to normal Haskell syntax.
- scotty79 6y agoI'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 6y agoStandard, 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 6y agoI 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 6y ago> 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 6y agoIt 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 6y agoSpace 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.
- tromp 6y agofilter ( > 0) also works.
- nervous_north 6y agoI 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!
- japanoise 6y agoContrary 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?
- logicchains 6y agoTo 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 6y agoIt'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
- masklinn 6y ago> What are the advantages of white-space insensitive code for refactoring and formatting? For refactoring, it's less error prone when you're using an editor without refactoring support for it, would be my guess. For indent/format, your guess is as good as mine, AFAIK programs don't care whether block separators are called INDENT or {. Though the parsing of the latter would be somewhat trivially simpler as you don't need to store a stack of indent levels.
- logicchains 6y agoWith 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?
- curryhoward 6y agoI 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.
- ithkuil 6y ago> why do C-like languages have so many ways to syntactically group things?) TL;DR math notation Because they are different things. Brackets are for types, curly braces are for "bodies" (struct definitions, initializers, statements, function bodies, control flow construct bodies), parentheses are for overriding precedence. There are obviously exceptions that don't fit in this general scheme: e.g. function call syntax is based on parentheses, so it's not just about precedence. All this is just a post-fact rationalization; this all comes from standard math notation. Math uses parentheses for function application. Math uses commas for arguments of functions of multiple variables. Math uses curly braces to state of things are defined (sets, inductive rules) etc. Math uses parentheses to override precedence. All the rest is that historical accident. Angle brackets were unused so they choose them for types. Square brackets for array indexing? No idea why
- deleted 6y ago[deleted]
- dan-robertson 6y agoThis is not an accurate description of notation as it is used in mathematics. All types of brackets (round, curly, square, angled, ...) are used in mathematics for grouping things. Typically parens for innermost small groups and other brackets for larger “outer” groups. Curly brackets may be used for sets but they are also used for different cases of functions, or as a more succinct and precise way of expressing sentences about multiple things than writing “foo, respectively bar” all over the place, or for Stirling numbers of the second kind, or for whatever other things an author might want. Other “structure making” notations like group presentations use angle brackets. Ideals are sometimes written with their generators in angle brackets, sometimes with round brackets. Similarly tuples or sequences may be written with either. Matrices are sometimes written with square brackets and sometimes round, and never with commas. Vectors typically are written with round brackets but may be square. Row vectors sometimes have commas. Function application is sometimes written with round brackets. Arguments are sometimes separated by commas, sometimes by semicolons, sometimes with one argument as a subscript or implicit. Application often omits brackets altogether. Sometimes the function goes on the left, sometimes it goes on the right. Now consider the few features which I find are relatively common to different mathematics notations are context, alignment and structure in 2 dimensions, juxtaposition, implicitness, and terseness. I think I see basically none of these in the common C/Rust style syntax you claim to be so rooted in mathematical notation, and indeed I would guess that you would oppose them. I don’t buy your arguments at all.
- li4ick 6y agoI mean...why not just go full OCaml at this point?
- k_bx 6y agoI 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”.
- wseymour 6y agoI'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 6y agoReasonML is similar. What do you find confusing about the syntax? Imo, Haskell/ML syntax is more readable and lightweight than traditional C-style syntax.
- agumonkey 6y agooh god, no top level patterns it's such a beautiful thing ..
- scotty79 6y agoIt has mathematical beauty. But I'm not a fan.
- sullyj3 6y agoI 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 6y agoThe fairly popular `LambdaCase` extension gives fib = \case 0 -> 0 [...]
- rattray 6y agoThe 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&geo=US&q=purescript https://trends.google.com/trends/explore?date=today%205-y&ge...)
- Vosporos 6y agoSorry, could you provide an example of those different styles?
- jasperry 6y agoI would have used the word "features" or "extensions" instead of "styles" but I agree with rattray's point, if I understand it correctly. 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. This makes me feel that, totally apart from the syntax, Haskell/GHC is still more of a laboratory for doing programming language research. Which is great for what it is; I would say Haskell's original motto "avoid popularity at all costs" still holds. I also had hope for languages like PureScript that make an opinionated choice about a subset of those features for the sake of a consistent development framework.
- unhammer 6y ago> each of which requires some deep knowledge of type theory to understand how it affects the language This is simply false. Quite a few of them are not much more than syntax sugars, e.g. with LambdaCase I can write eitherToMaybe = \case Left _ -> Nothing Right x -> Just x instead of eitherToMaybe var = case var of Left _ -> Nothing Right x -> Just x With OverloadedStrings I can write "foo" instead of (T.pack "foo") or whatever and it picks the right "pack" function based on the inferred type. OverloadedLists does the same for listy things, e.g. now [1] can be a literal vector and you don't have to say V.fromList [1]. TupleSections lets you write (1,) when you want a function that tuples something with 1 (so (1,) applied to 2 becomes (1,2)). NamedFieldPuns lets you write foo x = let myField = x + 1 in MyType{myField} instead of foo x = let thing = x + 1 in MyType{myField = thing} ----- And then there are a bunch of "Deriving…" extensions that don't require any knowledge either, you just enable the pragma, and it lets you say e.g. data X … deriving (FromJSON) instead of having to explicitly implement the FromJSON instance by hand. I have used Deriving a bunch and have no idea how they work :-) Looking through my main project, the only other extension I use on a regular basis is ScopedTypeVariables. That one's a bit more difficult to explain since you have to have some idea what the words "scope" and "type variable" mean, but basically lets you refer to a type variable from the outer function signature in the type signature of a where-clause. Normally, with foo :: Maybe a -> Int … where helper :: Maybe a -> Int the a's are seen as different types. With ScopedTypeVariables, you can say foo :: forall a. Maybe a -> Int … where helper :: Maybe a -> Int and the a's are the same type. So that lets you have explicit type sigs on helper functions that are restricted to the type of the outer function. (Though I am not an expert on this so maybe I've got it all wrong. But that doesn't stop me from using it to make stuff with.)
- amelius 6y agoHuh, 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.
- dreamcompiler 6y agoImproving Haskell with Javascript syntax is like improving a Mark Rothko painting by sprinkling glitter all over it.
- scotty79 6y agoIt'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 6y ago> 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 6y agoNot really. Python has exactly the same structure as all other popular languages. Lack of brackets doesn't make it much different. Ruby is weirder.
- rishav_sharan 6y agoAs 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 6y agoI 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 6y agoMay I ask you what kind of "magic" functions you have in mind ?
- quotemstr 6y ago&& 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 6y ago> && 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.
- namelosw 6y agoIt'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.
- hyperpallium2 6y agoC-like http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html?m=1 http://james-iry.blogspot.com/2009/05/brief-incomplete-and-m...
- _alex_ 6y agoI 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.
- platz 6y agowell, it's cute trick - not sure what the utility is.
- spankalee 6y agoWhoa, 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.
- IshKebab 6y agoHonestly 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. :-)
- javcasas 6y agoWithout 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 6y agoHow do people who are thrown by juxtaposition as function application and point-free style cope with Unix shell pipelines?