Hacker News new | past | comments | ask | show | jobs | submit login
F# 4.0 Preview (msdn.com)
249 points by noblethrasher on Nov 13, 2014 | hide | past | web | favorite | 71 comments

This is pretty cool, in my day-to-day language, Scala, we cannot do the following:

    [('a',1);('b',2);('c',3)] |> List.map String
In F# 4.0 the compiler infers that String takes 2 arguments and extracts the tuple accordingly.

In Scala we're forced to manually extract the tuple when the recipient function takes more than a single argument.

    def plus(a: Int, b: Int) = a + b
    List((1,2),(3,4)) map plus // kaboom
    List((1,2),(3,4)).map{case(a,b)=> plus(a,b)} // ok
We'll see where the Microsoft OSS movement goes. If in the not too distant future we can seamlessly take advantage of, for example, Type Providers and LINQ-to-SQL/Objects on Linux, I'll certainly give F# a deeper look.

Side note: the next 3 to 4 years will be huge in computing, IMO. Microsoft stack is coming to Linux and OSX, Oracle is finally pushing forward Java and the JVM, and FP languages in general seem to be picking up steam in terms of adoption. Good times ahead for everyone ;-)

And a another way to use tupled is:

    list map Function.tupled(plus)
Hereby additionally proving the old saying 'if you need help with a product don't say you need help because you'll get hit with RTFM, just say too bad you can't do X in product while it's easy to do in [competing product], and everyone will try to prove you wrong.'

> and everyone will try to prove you wrong

heh, how true, though more of an invitation; a strength/weakness of Scala is the fact that there's often more than one way to do the same thing (at least 3 ways have been shown with the current example). From what I've seen F# does not have this characteristic.

Anyway, ideally the Scala compiler would provide the same level of concision that for comprehensions do vis-a-vis flatMap/map boilerplate, thus reducing our example down to: `list map plus`, the bare essentials ;-)

Worth noting that the source for Function[0] indicates `Function.tupled` methods are slated for removal in future: "these functions are slotted for deprecation, but it is on hold pending superior type inference for tupling anonymous functions"


> In Scala we're forced to manually extract the tuple when the recipient function takes more than a single argument.

Is there no `uncurry :: (a -> b -> c) -> (a, b) -> c` in Scala?

    Prelude> let ap = flip map
    Prelude> [(1, 2), (3, 4)] `ap` (+)

        No instance for (Num t0) arising from the literal `1'
        The type variable `t0' is ambiguous
        Possible fix: add a type signature that fixes these type variable(s)
        Note: there are several potential instances:
          instance Num Double -- Defined in `GHC.Float'
          instance Num Float -- Defined in `GHC.Float'
          instance Integral a => Num (GHC.Real.Ratio a)
            -- Defined in `GHC.Real'
          ...plus three others
        In the expression: 1
        In the expression: (1, 2)
        In the first argument of `ap', namely `[(1, 2), (3, 4)]'

    Prelude> [(1, 2), (3, 4)] `ap` (uncurry (+))
Or some sort of `apply` method aliasing an n-ary function to a 1-ary function taking an n-tuple?

edit: there's a Function.tupled method so something like this might work:

    List((1,2),(3,4)) map plus.tupled

re: Your edit: Basically. Lift the method to a function first.

  def plus(a: Int, b: Int): Int = a + b
  List( (1,2), (3,4) ) map(plus _ tupled)

  > List(3, 7)
( I know there's already 4 or 5 answers... I just think mine's the prettiest. ;-) )

It's not as concise, but you could do

  List((1,2),(3,4)) map (plus _).tupled

Nicely done ;-)

However, not so easy to grok without knowing how to lift methods to functions in Scala and then applying the swiss army method of functionN types, `tupled`, to the result.

The F# equivalent one understands without needing to know special features of the language, it's pretty clear what's happening.

> The F# equivalent one understands without needing to know special features of the language, it's pretty clear what's happening.

The requirement to explicitly say that you want to pass a method around, not the value of the evaluated method was an explicit design decision in Scala, because very often it was not clear for developers what was happening (or more precise: they thought they knew, but something different happened).

> FP languages in general seem to be picking up steam in terms of adoption

I have been looking forward to this since I learned Caml Light at the university back in 1996. Same applies to LP.

It was been a long way.

> Same applies to LP.

LP = Literate Programming?

I read it as Logic Programming (i.e., Prolog).

I think you're right, but I'll at "Linear Programming" to the list.

Logic Programming, e.g. Prolog.

It's great to see the gradual improvements in F#. I think it's a brilliant language. I was initially not too sure, because, even though I've been coding C# for a long time, my first foray into the functional world was Haskell - which is a stunning language. But when it comes to plain old let's-get-things-done pragmatism, F# wins out imo.

It would be useful if someone knowledgeable and critical could explain clearly the use of this language. The marketing blather doesn't give me much. I'm not a software engineer, so this just seems like a bunch of syntax wankery. I'm probably wrong, I'm just looking for a brief explanation as to why.

Really short answer:

F# is to C# as C is to Assembler (I regularly use both C# and F# and don't quite agree with this, but it is defensible).

Short answer:

Programming, especially OOP, has a lot of prescriptions: things like coding against interfaces rather than implementations, using abstractions, the law of Demeter, avoiding mutations, prefer composition to inheritance, etc.

Basically, you can think of F# as a language that compiles down to C#, but follows all of the best practices without fuss.

Consider this example of F# code:

		type Shape =
			| Circle of float
			| Square of float

		let area s =
			match s with
			| Circle r -> Math.PI * r * r
			| Square sd -> sd * sd
		let perimeter s =
			match s with
			| Circle r -> 2 * Math.PI * r
			| Square sd -> sd * 4

Here is the moral equivalent in C#:

	 public abstract class Shape
	 	public abstract float Area();
	 	public abstract float Perimeter();
	 public sealed class Circle
	 	readonly float r;
	 	public Circle(float r)
	 		this.r = r;
	 	public override float Perimeter()
	 		return Math.PI * 2 * r;
	 	public override float Area()
	 		return Math.PI * r * r;
	 public sealed class Square
	 	readonly float side;
	 	public Circle(float side)
	 		this.side = side;
	 	public override float Perimeter()
	 		return 4 * side;
	 	public override float Area()
	 		return side * side;
A couple of things to note:

* The C# code needs 5 times as many line as the F# code (adding a new shape to F# will require about 3 lines, but the corresponding C# class definition will be at least 15 lines).

* The F# code is idiomatic, but hardly any C# programmer seals classes or defines them as immutable by default, even though it is a good practice.

That said, there are some advantages that C# enjoys. Consider our example code: Even though C# requires more lines of code to define a derivative of Shape, at a certain point it will always be easier to add new classes to C# than the corresponding variant to F# (see "The Expression Problem" - on the other hand, adding new functions that apply to Shape will be easier in F# than adding the corresponding new methods in C#). Also, F# is supposed to be a hardcore statically-typed language, but there are some advanced concepts (e.g. type classes) that are easy to realize in C# yet not in F#.

Well, C# idiomatic would be rather

  public interface IShape 
      float Area { get; }
      float Perimeter { get; }

  public Circle : IShape 
      readonly float r ;

      public Circle(float r)
         this.r = r;
     public float Area { get { return Math.PI * r * r; } }
     public float Perimeter { get { return 2 * Math.PI * r; } }

  public Square: IShape 
      readonly float a ;

      public Square(float a)
         this.r = r;
     public float Area { get { return  a * a; } }
     public float Perimeter { get { return 4 * a; } }
Also, with this one you can create new Shapes in another project. With F# solution there, you must have access to original code.

I agree that it would be more idiomatic. I disagree that it is good.

Abstract classes have disjunctive semantics (logical OR) whereas interfaces have conjunctive semantics (logical AND).

The actual important thing that I wanted to capture is that an instance of Shape can only be one kind of shape at a time. With an interface a class could be more than one kind of Shape.

    interface IFoo : IShape
        //some stuff

    public class SomeShape : IShape, IFoo
        //I am a circle AND a square!

You've just described the expression problem.


I actually think C# (and many OOP languages) gets around this fairly well, by having virtual and extension methods. Many types of functions can be added easily without needing to go back through every inheritor.

* EDIT - realised I responded with an answer not related to the topic; I'll leave this here as a point-of-reference for the OO side of F# *

Extension methods don't extend the type. They extend the functionality attached to the type.

F# has these too [1] (actually more powerful versions):

The thing about using sum-types (the original Shape example) is that they're not supposed to be extended. You're defining the range of the type, which allows for powerful inference of completeness when using them. If you need extensible classes then F# can do those too, it can represent interfaces, abstract classes and concrete classes [2][3][4], and can even generate ad-hoc classes from an interface by using Object Expressions [5].

I personally try to stick to the pure functional approach, but it can be very handy when interoperating with the .NET framework, or other C# based libraries.

[1] http://fsharpforfunandprofit.com/posts/type-extensions/

[2] http://fsharpforfunandprofit.com/posts/classes/

[3] http://fsharpforfunandprofit.com/posts/inheritance/

[4] http://fsharpforfunandprofit.com/posts/interfaces/

[5] http://fsharpforfunandprofit.com/posts/object-expressions/

Another thing is that the F# example has equality semantics built in, whereas in the C# example, you'd have to override Equals (and GetHashCode), adding more lines still (for some tedious work that you shouldn't have to do).

Your F# example can be more concise:

    type Shape =
        | Circle of float
        | Square of float

    let area = function 
        | Circle r -> Math.PI * r * r
        | Square sd -> sd * sd

    let perimeter = function 
        | Circle r -> 2.0 * Math.PI * r
        | Square sd -> sd * 4.0

Well, that's just... neat.

I noticed you sealed the C# classes. What if you want to keep it extensible, which makes sense? How will that extensible pattern matching look then?

Also would be interesting to see how long would C#6 code be (twice as short?).

Apart from the sample, I also don't understand why F#'s naming patterns are not consistent with the rest of .NET (in terms of starting letter case). Feels alien.

Also how come this was considered a sane syntax for arrays?

[|1; 2; 3|]

instead of

[1, 2, 3]

Even Haskell's syntax is less alien.

Not to mention indexers.

Well, programming languages do have a prescriptive aspect. Arrays in C# 1.0 were more fundamental than List whereas the situation in F# 1.0 was the reverse, and F# doesn't really want you to use arrays as much as it wants you to use list.


Personally, I always mark my classes as either sealed or abstract. In OO terms, I only care about extending the Shape class, not the individual subclasses because those themselves are are already extensions... of the Shape class. If I did want to extend, say, the Circle class, I would probably make a new abstract class called Ellipse that derived from Shape and then derive Circle from Ellipse.

But, I don't really think in strict OO terms any more. C# has a decent type system (despite what my fellow ML programmers might say), but one of the mistakes of the language (i.e. the spec) is that it conflates types with classes. Those are different things. You may see three classes, but I see one type. In this case it's a sum type called Shape that ranges over Circle and Square. A sum type , as you may know, is just the type-theoretic version of logical OR.

Indeed, it wasn't until I learned about sum types that I finally understood why you would use an abstract class as opposed to an interface: abstract classes are for when you want to say that a Foo is a Bar OR a Baz OR a Biz whereas interfaces are for when you want to say that Foo is a Bar AND a Baz, AND a Biz.

> "In this case it's a sum type called Shape that ranges over Circle and Square"

How do I extend Shape to include Triangle without modifying the current code (e.g. in a separate file)?

You would have to modify the code, and as I mentioned, it can be pretty painful in F# and other ML languages if you already have a bunch of functions that apply to Shape.

Subclassing is a good and useful tool that simply works better in C# than F#. But, just as importantly, class hierarchies are often a poor way to model a problem.

Fair enough, thanks for answers.

You're welcome.

It just occurred to me that you may have been asking about extending Shape in the C# example. In that case, you'd just subclass Shape as normal[1]. Some people argue that sum types shouldn't be extended, but I never really understood that. Basically, C# lets you define unbounded sum types (in the form of subclassing) whereas idiomatic F# more or less demands that you know up front how many variants you're going to need.

[1] Although, sometimes I do define my classes to prevent this by marking the constructor(s) of the abstract base class as private, and then writing the derived class definitions within the body of the base class.

I have seen opinions that C# is good for architecture and F# is good for implementation of components. I might opt for such an approach. Really wish I had a default non-null immutability in C# though.

F# is ML family (like ocaml) With F# you use tuple a lot so is nicer have ',' as separator for tuple parts.

  let tuple1 = (1, 3) //tuple (int, int)
  let tuple2 = 1, 3 //same as before, parens are optional

  let list = [ 1; 2; 3 ] //list of int

  let array = [| 1; 2; 3; |] //array of int

  let listOfTuple1 = [ (0,0); (1,2); (4,5) ] //list of tuple (int, int)
  let listOfTuple2 = [  0,0;   1,2;   4,5  ] //same as before
see https://dotnetfiddle.net/vzeZvJ

nice and fast syntax guide http://fsharpforfunandprofit.com/posts/fsharp-in-60-seconds/

I think the question is "why has ML such a nice syntax, and OCaml managed to make it worse all across the board"?

IIRC, F# is derived from (or, at least, heavily influenced by) OCaml and that's the OCaml syntax for arrays. OCaml lists (I don't know F#, but presumably it's the same) have the [x; y; z] format. Note that lists and arrays are different: They're both homogeneous, but arrays have a fixed length while lists can shrink/grow; indexing arrays is O(1), whereas you have to traverse lists at O(n). In functional programming, it's a very common pattern to work with lists, hence the nicer syntax.

There are only so many ASCII symbols to use for separators and brackets when creating syntax for literals. Think of [| and |] as〚 and 〛 (double square brackets), then it doesn't look so bad, I think.

Yeah, it looks a lot cleaner - but if you make that code available as a library then other people can't add new shapes easily, or deal with shapes that have more than one length (e.g. a rectangle, which has two).

Well, yes, you can add a rectangle quite easily:

    type Shape =
        | Circle of float
        | Square of float
        | Rectangle of float * float
The thought about adding new shapes (mentioned several times in this thread) is just misplaced. If you're releasing library code people should not be extending your built-in types, that's bad form -- consumers of a library should interact with it through interfaces only.

The flipside is that its very easy for your library users write a new function that takes a Shape as a parameter. If you model things with a class hierarchy its easy to add a new Shape subclass but you can't add any new methods to the Shape interface.

That comment about shapes with more than one defining size property is very valid.

This is a rather poor example. If you distribute the C# code above as a library, people can extend and introduce another shape, while they cannot do it easily with you F# code.

I did mention the Expression Problem[1] in my comment, and explicitly called out subclassing as a particular advantage of C# (the OP asked for criticism of F#).

Also, even though F# can also subclass, that facility is a bit weak since it can't define protected members.

[1]http://c2.com/cgi/wiki?ExpressionProblem - funny thing is that the linked page coincidentally uses the exact same example code.

Good explanations already, but I'll add my two cents. F# has:

* Rich language constructs that encourage pithy and correct code (e.g. arrays and lists are a language type rather than a library datastructure and the syntax facilitates implementing very readably and succintly common operations on them)

* The combination of algebraic data structures and pattern matching enables succinct implementation of solutions for lots of common programming problems. This was perhaps the biggest wow feature of the language when I learned to use it well.

* Functional languages tend to encourage immutability. F# works idiomatically with mutable data as well, thus being well suited for e.g. numerical code. I would call this letting us have the cake and eat it too.

* I don't think there are any specific downsides to F#. Some programs are better expressed in C# still but the .Net platform allows one to access those classes seamlessly from F# side.

IMHO, these are all wins. There's not much unnecessary language wankery in F#, it was developed as an industrial tool from day 1. so most features have some rationale behind them.

F# is a general purpose language. It can do anything Java/C# can do, only shorter and safer.

Here is an example of a simple language tool not in Java/C# that makes it easier to write, read, and is safer. http://deliberate-software.com/function-pattern-matching/

F# can also call anything written in .NET, so it's easy to start using it right away.

The biggest complaint people have is that it is a totally new language, and the parts that make it simpler and safer take effort to learn. In all honesty, several developers I know don't want to learn it, mostly because they only know C#, and do not believe the claims of speed and safety. They cannot imagine what could be different, so a day or two in, they just think of it as "syntax wankery", and never get past that point.

Really, the different syntax just makes it about a third the size of the equivalent C#. That alone is fine, and usually is the reason people prefer languages like Ruby/Python. But the real power comes from deeply understanding computation expressions, the LINQ equivalent, and F# data structures. Those three allow code that is much safer and easier to write, without sacrificing any functionality.

At my work, (Winforms app and an MVC4 web site) I use it anywhere I'd use C#.

It's a functional language for the .NET platform.

So you'll want it if you want a functional language and you want to use the .NET platform.

Does that answer your question?

F# is a hybrid language just as C# is. Just a different flavour of the mix.

Yes a longer answer is that it is "functional first" just like C# is "OO first". It's safe to say that f# is much closer to ML than Java tough, so it's very much a functional language in a way that C# is not.

This post is about latest feature added to f# language (syntax cleanup, speed, etc)

why use a functional language? see http://fsharpforfunandprofit.com/posts/ten-reasons-not-to-us...

Why use f#? see http://fsharpforfunandprofit.com/why-use-fsharp/ (concise for programmers) or http://fpbridge.co.uk/why-fsharp.html (more high level)

more info about fsharp at http://fsharp.org/

my take:

#ecosystem - vibrant and friendly community - open source (long time ago, use pr, wrote by community) - cross plat (linux/mac/win/ios/android) - is .NET, same standard library as C# or VB.NET and virtual machine (CLR). Finally open source - use nuget components written for .net - third party component with commercial support

#language - fun to use - concise, i can easy write code without boilerplate - multi-paradigm (functional first, but can do oop like c#) - easy interop with c#, native - fast - help write correct code (no null reference => no null reference exception, pattern matching, - easy async, parallel, gpu - unit of measure (like 1<m/s> )

and a lot, read the links above for a better (and faster) summary

I'll try to give a pragmatic example. At work, we've got a lot of analytics code in C# for model-estimation, pricing, etc. I spend a lot of time tweaking models, running them, then extracting and analyzing the results. F# works very well as a scripting language for me, where otherwise I would be using something like IronPython.

The results-processing I could do from anything (R, python), but scripting the run (running N random samples of something, doing simple cross-validation, manually hacking a pseudo-hierarchical model, etc.) is much easier when I have direct access to the C# API.

Since the codebase is always-evolving, the type checks of F# (as opposed to IronPython) are useful when going back to an old script.

I also just enjoy using F#. I'd been hoping to learn a ML-family language for years and working at a F#-friendly shop has let me do that.

Very cool. After my M.Sc. I'm going to need to find a job, and since OCaml jobs are pretty much inexistant in Montreal, F# is my backup plan.

Good thinking to be considering the demand. Why not a remote job? Also consider the trend. There's a site that ranks language popularity on a periodic basis.

Normalized collection modules is a big plus. It was always a pain having to cast something out of one thing and into another just to get some method that should have been there in the first place. Same goes for slicing.

Some good stuff, guys!

I can't wait for .NET to be ported to Linux to try this, it looks awesome.

Stay tuned: There are already a number of docker containers with F# on them using Mono. Because the F# compiler is open source, you can probably create your own container pretty easily based on the preview builds. https://github.com/crosbymichael/fsharp-docker

It works just fine on Mono. Use the current F# from git.

If I've already been learning Haskell, should I keep going or stop, drop everything and learn F#? I'd like someone with F# and Haskell experience to answer.

Depends on your requirements. I use F# day-to-day, but I think Haskell overall is a better language. There's some ugly aspects to F#, like its OO grammar, lack of typeclasses and seeming randomness to the casing (sometimes camelCase and sometimes PascalCase). These are all artefacts of it being a pragmatic tool in a toolset: its requirement to work with other .NET languages and frameworks (and Mono).

So for a bit of ugliness, and some loosening of the type-system shackles, you get a whole ton of stuff.

Haskell as I'm sure you're aware is much stricter and much harder to interoperate with. But much more refined as a language. Whilst you do get the "If it compiles it will probably work" thing with F#, it's nowhere near the level of Haskell. Haskell tends not to play as well with Windows, but again it depends what you're doing. I've had very few problems with Haskell on Windows by writing stand-alone services that talk to the rest of the world through RabbitMQ.

So if you're writing something that must absolutely be provably sound, doesn't need to talk to much else, then I'd go with Haskell. If you need lots of core Windows features it'd probably be best with F#.

I went from Haskell to F#, and I'm glad I learned Haskell first because it gave me a much stronger grounding in functional concepts. It's much easier to 'break the rules' in F#.

I hope that helps.

Yes, thank you for your explanation, it was great.

That is why I've started with Haskell too (6 months in now), because it teaches you the fundamentals about FP, and is strict about it (a good thing in my opinion).

That being said, I will continue to use Haskell. I know C# and I'm sure the jump won't be too difficult if I ever need it.

Yep, the jump from Haskell to F# is quite easy. It's a shame that F# doesn't put Computation Expressions up front like Haskell does with monads. The times when I feel like I'm getting into a mess with F# are nearly always fixed with monads (passing state around for example).

The nice thing with F# is that [if you have C# experience] you can pretty much just fall back to the standard .NET framework library if you get stuck. And the fact that F# supports dot notation means intellisense works. I've found over time I use the core BCL less and less as I retreat to a more pure functional approach however. Again, a good grounding in Haskell will help you there.

F# is a wonderful language, albeit I'm still getting used to style.

Is anyone here using F# for real project? It would be great to see it in wild.

Bunch of folks are. I've used it for several. I think there have been a couple of AskHNs for this.

I'd show mine but you wouldn't see any code! My latest is http://newspaper23.com

I use F# to generate static pages. This allows me to completely decouple the back-end from the display. I don't have interactivity yet, but I really don't see a need to add a framework to get it. F# and mono allows me to shoot for brutal simplicity. I like that. Many times projects that might be huge monstrocities in other languages turn out to be just a few well-coded modules running as Unix-y microservices in F#.

People are starting to give F# a lot of love as a .NET language, then wondering "Where's the framework?" I'm coming around to the conclusion that it works best when there is no framework. Fun times ahead.

> People are starting to give F# a lot of love as a .NET language, then wondering "Where's the framework?" I'm coming around to the conclusion that it works best when there is no framework.

Yes, in F# and other ML-like languages you tend to use libraries more than frameworks.

(I'm the original poster, and I've been extolling the virtues of ML-style functional programming throughout this thread, but I still owe you an email explaining why I think OOP is ultimately better than FP)

Tachyus uses F# almost exclusively. We have had great success with it. Just released 2.0 of our stack to production. After a week, still no issues. We use it for server-side web development in Azure, iOS app with Xamarin, and Raspberry Pi Linux. Fantastic integration with SQL Server throught the SqlClient Type Provider. It's great having one language across platforms.

How does Raspberry Pi fit into the whole picture? Is it used as an 'Internet of things' device to collect telemetry data?


I used it for an internal app that's getting used by several of the top global pharma companies to solve an optimization problem. I would choose F# again in heartbeat for that sort of project: its expressiveness let me implement the core algorithm in just a few hundred lines of fast, readable code, and its seamless interface with Microsoft-world allowed me to to embed it in a standard "Enterprise" stack (a C#/WPF desktop app as well as an ASP .NET webapp).

Jet.com is using F# as their core language. (and hiring) http://techcrunch.com/2014/09/16/quidsi-co-founder-raises-an...

I've used it for parts of two commercial projects (not counting side projects). One was a small parser -- C#'s parser options were uninspiring while FParsec (based on Haskell's Parsec) was great. The other was to simulate a client-server algorithm we were developing under different network situations. F#'s ability to express algorithms concisely was a real win there.

Side projects have mostly been stats/data based: using type providers to mash together different data sources, with visualization via FSharp.Charting.

I use it in telecom (VoIP). At peak, we were doing 1 billion calls a day. All routing decisions, F#. All call records, F# (on Mono).

I've also used it in network indexing, processing 5TB of SIP signalling a day on a single server, then indexing and storing each packet for later searching. This is now used in the voice arm of a large public telco to provide troubleshooting.

F# is a joy to work with and every time I use C# it's annoying.

F# on Mono, that's great. Did you face any major roadblocks with Mono/F# in production?

No, honestly, the biggest issue was just remembering to install the F# libraries.

Actually, the biggest issue is mono-service. Since we run cross platform, we used the Windows service API instead of writing a normal daemon. This has been a source of "random" issues with getting it to start. But that's just our fault for not changing 10 lines of code and just running it like every other Linux daemon. Similarly, some code depended on file locking (because FreeSWITCH's CDR writers don't properly write to files) which doesn't work on any popular Linux file systems. There are probably some other little issues where we made a dumb Windows only assumption.

All in all, it's been smooth sailing. Stuff just works. We develop and test exclusively on Windows, then deploy the binaries to Linux. I can't say enough good things about F# and about Mono.

Also, I don't use it on Linux, but F# Interactive would only work on some installs. A problem with readline iirc. I'd guess that developing on Linux will be more rocky than using Visual Studio.

I'm using it on a number of proprietary projects. Check out [1] for a ton of 'in the wild' projects:

[1] https://github.com/fsprojects

Applications are open for YC Winter 2020

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact