Morning Coffee 127

F# Hawkeye : Assorted Not-So-Goodness

(Harry is @ DevTeach in Vancounver with his family this week. He was hoping to still do Morning Coffee posts, but that’s turned out to be infeasible. So instead, you get a series of pre-written posts about F#.)

It’s not all puppy dogs and ice cream with F#. Here are a few things that I didn’t like about the lanugage.

Linear Scoping

In C#, a given piece of code is able to call any function it wants to (limited by CAS and visibility of course). If I define two functions, the first can call the second even thought the compiler has never seen the second function when it’s parsing the first.

F# has linear scoping like C++ does. You can’t call functions that haven’t already been defined in the file (or a previous file that’s already been fed to the compiler). This makes writing mutually recursive functions (A calls B, B calls C, C calls A) fairly annoying. Typically, in F# we declare functions with “let”. But in the Additive function above, we’re declaring the function with “and”. By using “and”, we’re basically chaining together function declarations into a logical unit. Then, you mark the first function declaration in the chain as recursive, and now those methods are enabled for mutual recursion. Not exactly intuitive.

Frankly, I like C#’s ability to bind to methods that haven’t been declared yet. I wonder if this is an intrinsic issue with FP or F# scoping rules, or if it’s something they could fix if they took the time.

No Method Overloading

In my CheckForToken method, I use a string type to hold the token I’m looking for, since tokens can often be multi-character. However, for one character tokens, this is over kill. Not just in terms of creating a string object to contain just one character, but also in how I pattern match the token against the input string. If we’re only looking for one character, we can skip recursion entirely. Yet there’s no way to define two functions called Token that have different signatures.

Given type inference, this isn’t surprising, but it’s still a little annoying for folks coming from C# land.

Limited VS support

More evidence of a rotted brain. F#’s integration into VS is limited at best. It does syntax highlighting and debugging, but that’s about it. The problem I keep running into is that I have two projects – my main project and my test project. Even though I’ve define the test project as being dependent on the main project, it doesn’t automatically compile the test project when I change the main project. So I keep doing something like fix a bug, recompile, then run NUnit to see if the light turned green. It doesn’t, because I haven’t rebuilt the test project and it’s still referencing the old version of the main project. Now that it’s a “real” product, I’m hoping to see better integration into VS08. Maybe even an F# Express that leverages the new VS08 shell?

F# Hawkeye : Assorted Goodness

(Harry is @ DevTeach in Vancounver with his family this week. He was hoping to still do Morning Coffee posts, but that’s turned out to be infeasible. So instead, you get a series of pre-written posts about F#.)

Significant Whitespace

If you’re a Python programmer, you already know this one. Instead of delineating code blocks explicit with curly braces or begin/end keywords, F# uses whitespace. Code blocks are indented relative to their parent. This enforces readability standards as well as conciseness. You can see that in the code Additive function above. Technically, this is optional in F# if you specify the #light compiler option, but pretty much all the docs and books assume this by default.

Custom Operators

This is minor, but cool nonetheless. Many languages let you overload existing operators like + and *. However, F# goes a step further and also lets you create custom operators. You just pick a combination of symbols that isn’t already being used and define a function for it. For example, in my parsing code I wanted a simple way to adorn my input parse strings in my tests so that I could later easily change their type if I changed the type of NextChar and CheckForToken as described above. I defined the “double bang” operator !!. Currently, double bang converts a string into a character list, but originally it simply returned the string since I had written my Char and Token classes in terms of string.

F# Hawkeye : Type Inference

(Harry is @ DevTeach in Vancounver with his family this week. He was hoping to still do Morning Coffee posts, but that’s turned out to be infeasible. So instead, you get a series of pre-written posts about F#.)

For you LINQ early adopters, you may think you know everything about type inference, but F#’s uses it much more extensively. In C#3 , you can write “var o = new SomeObject()” and the compiler is smart enough to figure out the variable o is of type SomeObject. Saves some typing, but it’s not exactly brain surgery. F# can not only infer the type of local variables like C#, but it can also infer type of a function’s input parameters and return value based on how those variables are used in the function. For example, in the Additive function, F# can infer that the “input” parameter is a char list because Token takes a generic list and ‘+’ is a char.

F# automatically “generisizes” the functions you write. So if you write a function for traversing a list, by default it will work on a list of any type. You don’t have to explicitly declare the generics, F# automatically makes your code as generic as possible, based on your usage of the variables.

What’s really interesting about this approach is that changes to parameter or return types in a low-level function can have a rippling effect up the stack. In my parsing code, I haven’t settled on the type I’m going to use to represent the string to be parsed. My tests are all short strings, so F#’s intrinsic char list type is fine. However, I don’t know how well that will work for longer strings like a typical input file. F#’s native parsing tools (based on lex & yacc which I dislike) have a special LexBuffer class to represent the parse string. However, I’ve written my code so I can change the type of the lowest-level functions (NextChar and CheckForToken) and not affect the rest of my code. That’s pretty wicked.

Type inference does have a downside. I guess VS has rotted my mind, but I’m hooked on Intellisense. The BCL is too big to remember all the classes and all the method parameters. Intellisense is kinda like Google a web search engine. If you sorta know what you’re looking for, Intellisense helps close the gap to find it. Otherwise, it’s time to break out the docs. However, if you’re inferring type based on usage, Intellisense is out of luck. Honestly, there have been times where I’ve put in an explicit type declaration to get Intellisense to work, written the code, then removed the type declaration.

F# Hawkeye : Pattern Matching

(Harry is @ DevTeach in Vancounver with his family this week. He was hoping to still do Morning Coffee posts, but that’s turned out to be infeasible. So instead, you get a series of pre-written posts about F#.)

Most FP languages include some type of pattern matching, and F# is no exception. At first blush, pattern matching looks a little like a switch statement, but it’s much more powerful. Where switch statements typically only do simple matches such as “does this variable equal this constant?”. In F#, you can break apart types, use wildcards even pass the potential match data into a custom function to determines if there’s a match. Of course, you can also do your more run-of-the-mill “does value equal constant” comparisons as well.

The problem with most functional language is that while pattern matching is powerful, it’s not particularly extensible. As Don pointed out in a recent paper, this becomes a real problem when trying to integrate FP with OO. OO is designed to hide details behind abstractions. Yet those abstractions can’t be used in pattern matching. Luckily, Don and the F# Guys (sounds like a band) have invented an extensible pattern matching syntax called Active Patterns to deal with this problem. Basically, in more recent versions of F#, you can adorn functions with special syntax so that you can use them in your pattern matching clauses.

This turns out to be wicked cool for writing parsers. I’m building recursive descent parsers, so each grammar production is implemented as a function. Yet, since I’m using the active pattern syntax, I can use them in pattern matching clauses. This allows me to chain together functions in a single match clause rather than having multiple match statements. And it’s very readable. For example, the function to recognize the grammar production Additive  <- Multitive ‘+’ Additive | Multitive is translated into the following F#:

and (|Additive|_|) input =
    match input with
    | Multitive(v1,Token '+' (Additive(v2, input))) -> Some(v1+v2,input)
    | Multitive(v,input) -> Some(v,input)
    | _ -> None

The weird “bananas” around Additive on the first line indicate this is an active pattern. Multitive and Token are also an active patterns. This syntax is a little parens heavy, but otherwise, that translation from grammar to F# is nearly declarative. It almost defeats the need for having a parser generator when building a parser is this straightforward. Almost.