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#
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#
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-...
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.
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.> 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 applicationThe same as Haskell
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.