4 ms·
There is a better approach by using statically typed functional languages like F#, Ocaml, or Haskell. They don’t need to have the type declaration as most thin
by whb07 7y ago
There is a better approach by using statically typed functional languages like F#, Ocaml, or Haskell.
They don’t need to have the type declaration as most things can be inferred.
So you get the feelings of writing Python with the full suite of benefits of a strongly typed functional language when using say F#
- mixmastamyk 7y agoI’d be very interested if any of these decided on non-atrocious syntax. Any progress on that front?
- whb07 7y agoCan you expand on this? Haskell or F# have less noise than Ocaml. Plus with F# you can just pipe things neatly. I started and still love Python, these languages have ALOT of stuff going for them that blows the standard language used nowadays out of the water. Download .netcore and setup VSCode + Ionide plugin and you’re ready to rock and roll (fastest IDE setup). As you write your code, you’ll see the function signature and what the compiler can infer from your code. Also checkout the basic intro, syntax is very clean and straight to the point. https://docs.microsoft.com/en-us/dotnet/fsharp/introduction-to-functional-programming/ https://docs.microsoft.com/en-us/dotnet/fsharp/introduction-...
- mixmastamyk 7y agoYeah, f# is not bad. How is it on linux, are there enough third party libs? Not inclined to use MS tools unless both reqs are met.
- whb07 7y agoI’ve used it on osx and it runs great actually, and the Linux story is the same. The standard .NET libraries are obviously sharpened steel and the third party libs are fewer than say NPM but higher quality and address some of the missing pieces. Though again, the F# batteries are great and the .NET libs cover most if not all of your needs. Check it out. You get sweet syntax, great compiler and tooling, and you won’t suffer things like nulls etc. Also parallel and or concurrent work is a breeze since everything is immutable by default, and it makes it ugly to try to stick it to a mutable procedural or oop style. I highly, highly, suggest you check it out. It’s the step child that Microsoft refuses to acknowledge in full force. But I think that story will change soon as they realize how GIANT the Python sector is and so F# is a great gateway drug into the .NET world. edit: By the way I used to hate on MSFT for the longest and I haven’t used Windows in over a decade. But F# is fire.
- mixmastamyk 7y agoCool, yes MS has made great strides but I still don’t trust their telemetry needs.
- ben509 7y agoI think the issue with Haskell's syntax is it has always been a research language that has evolved very rapidly, and it shows. Honestly, I'm more impressed than anything that it manages to remain quite usable in spite of this. There are small warts like unary negative, others are things like templates that were added later. The most obvious, and most syntactic, is having braces and indentation layout. I've found, after using mostly indentation layout, that I've forgotten exactly which structures are blocks. Others are simply bad designs, like data record accessors. A `data` declaration is declaring accessor functions for me, whether I ask for them or not, putting stuff into my namespace. Then there are more kludges to work around the obvious problem of having fields with conflicting names. (Oddly, there's a very elegant update syntax, and pattern matching works beautifully. It seems like a simple tweak to that could have avoided accessor functions entirely!) Some issues are inherent to the design, and reflect a conflict between the language designers and the users. Ubiquitous currying is a great example. Making all functions unary is mathematically very elegant, but it doesn't reflect the way we usually think. If I intend to declare a function f(a, b), I simply can't. Its signature must be A -> B -> C. That's especially odd when you're declaring a binary operator. I'm looking at this through the lens by which Scheme reformed LISP's defun: (defun square (x) (* x x)) (define (square x) (* x x)) It's subtle, but it reflects a nice minimalism in syntactic design as it uses the same structure for declaration and for application.
- tome 7y agoI can't understand what you mean, because > A `data` declaration is declaring accessor functions for me, whether I ask for them or not, putting stuff into my namespace It won't if you don't use record syntax. If you want the accessors, use record syntax. If you don't, don't. > If I intend to declare a function f(a, b), I simply can't Sure you can. f(a, b) = a + b > it uses the same structure for declaration and for application The same as Haskell
- ben509 7y agoThere's a core dispute here, and it's a pretty common one that can never quite be resolved. The practicality argument I think you're making is necessary when you're working on an existing language feature, and that's because you're invariably forced into tradeoffs. The argument from design I'm making is more appropriate to a completely new language feature; the more your design is based on math and especially the linguistics and psychology of user's intent, the fewer clever hacks the user has to make and the fewer tradeoffs you'll be making in the future. Haskell did get a lot of design choices right because they had smart people who worked through the math, but I think regarding linguistics and psychology, it's much more of a "greybeard" language. > It won't if you don't use record syntax. "Don't use that feature" is simply acknowledging a feature is broken, it doesn't make it not broken. And you typically need named fields because you have complex code and want it to be maintainble, that's also when you don't want your namespace polluted. > Sure you can. f(a, b) = a + b How does that work declaring an operator? You're trying to write a binary function, but to do that thing you have to do something else, write a unary function that accepts a tuple. It's hard to claim that "oh, n-ary functions are really just functions that accept n-tuples" when Haskell plainly doesn't believe it. That's evident in the fact that you lose the benefits of currying, sections, etc. > > it uses the same structure for declaration and for application > The same as Haskell Nope. f :: Int -> (Int -> (Int -> Int)) -- Parens for clarity f a b c = a + b + c x = ((f 3) 5) 2 So we have two mismatches here: 1. The associativity of type is the reverse of application. 2. Neither of them reflect the simple case where I want to call a function with three arguments. And, look, I get that math is what makes #1 an issue. I'm more an advocate of ubiquitous partial application: f :: (Int, Int, Int) -> Int f(a, b, c) = a + b + c x = f(3, 5, 2) y :: (Int) -> Int y = f(3, 5, ...) z = y(2) It's stating exactly what you mean, and still has the benefit currying, and it's clearer to the reader what's a function and what's a value. Function types become more complex, so I get why currying is attractive, but, again arguing from design, that's letting implementation drive interface. And the math behind currying is certainly sound, but it's obscuring the fact that an n-ary function plainly isn't a unary function. They're just two different things.
- weberc2 7y agoI actually find that excessive type inference is much harder to understand. It’s almost like the worst of dynamic and static types. You have no idea what the types are, but you know it won’t compile because of a cryptic error message.
- haecceity 7y agoWith f# the ide can annotate types of expressions for you.
- Too 7y agoSounds like c++ templates, it is really the worst of both worlds. When something throws an error you don't know if it's the caller, the callee or the provided type that is wrong, and usually these errors come five gazillion layers down the call stack. They are introducing 'concepts' in c++20 to remedy this by removing the need for inference and constraining the type at the usage site.
- zozbot234 7y agoYou can usually get the compiler to tell you the inferred type of an expression, if only by writing in one that's obviously wrong, e.g. () and looking at the resulting error message. Some languages, e.g. Haskell support a "holes" mechanism that formalizes and expands on this 'trick' to enable a kind of 'dynamic', exploratory programming even in a wholly static language.
- weberc2 7y agoFair point. Perhaps my issue was less about the visibility of the annotation and more that the types in functional languages tend to be more abstract or complex (e.g., monads, functors, etc) and harder (for me) to reason about despite the code being terser.