Pages: 1 2 3 4 5 6 7 8 9 10 11 ... 63 >>
So I got a chance to see a Kinect in action today, although I didn’t play myself. Here are some impressions.
I just started work at Bing, so don’t expect many (any) blog posts for the next month or two.
Actually, the real reason is that I have stopped working on Fing until I can finish my dissertation revisions. There aren’t many—I estimate about a month’s worth—but who knows how much furniture/clothes/computer/phone shopping will interfere on the weekends. If there’s one thing I’ve learned during the move, it’s that serious shopping takes FOREVER. Also that it’s really tiring.
But that means that I won’t have anything super interesting to write about in the form of Fing code analysis. Or even anything at all, since I guess “super interesting” is about three notches about the normal fare for this blog.
Oh, and I just went through the Mandatory Online Legal Training today. So let me remind you: I do not speak for Bing or Microsoft on this blog. Even if I do discuss Bing, I do not do it in an official capacity, and my statements should not be taken to be indicative of any Bing policies or future directions. I’m not even going to tell you my microsoft e-mail address, except to say that it’s like 10 times better than the alphabet soup I got from Indiana University. I must have been at least the 23rd Nathan Sanders to go to IU.
And now that I know all about trademark law, who knows whether Fing will continue to be called Fing. I may have to change the name to F#$`ing after all.
Now that I’ve been using F# for real code for almost a month, I’ve noticed some warts. That’s pretty fast for a new language, but I am coming from Haskell, which is very similar. So some of these are warts on Haskell too, and others are complaints that F# is not Haskell.
Those are mostly syntactic warts that I noticed. Nothing major, and CERTAINLY much improved from O’Caml, whose designers have paid very little attention to syntax. The semantic warts are a little more serious.
let rec merge firstArg secondArg = match firstArg,secondArg with | [],[] -> ...
Dual .NET/ML heritage:
// struct
type Point3D =
struct
val x: float
val y: float
val z: float
end
// record
type Point3D = {
x : float;
y: float;
z: float;
}Seq.append (Seq.filter ((=) foo) x) seq2
let f l = l |> Seq.filter ((<>) foo) let main = printfn "%s" (f [1;2;3]) // `main` has to appear after `f` since it references `f`. // But that means the type of `l` can't be (completely) inferred // `because `f` has no context for it.
Monomorphism restriction:
// both fail because generic functions as values are not allowed let f = g >> h >> i let csv = sepBy (pchar ',') (many anyChar)
No 1st-class methods/properties:
// both fail because neither properties nor methods // can be used as functions let xvalues = Seq.map Point3D.x points let allsplits = Seq.map (string.Split [| ',' |]) filelines
let sequence : ??? = ???I’m pretty sure even if you could write generic code for sequence, the type is impossible to express in .NET: list<’m<’a>> -> ‘m<list<’a>>.
let rec map f = function
| [] -> []
| (x::xs) -> f x :: map xs
// NOTE: Example only! Do NOT write List.map this way.
The last argument is the most likely to be pattern-matched anyway, probably about 90% of the time.
Seq.filter ((=) foo) x |>Seq.append<| seq2But that only gives you infix functions, it doesn’t make prefix operators any prettier.
Monomorphism restriction:
// make a syntactic function or annotate type let f x = x |> g |> h |> i let csv : Parser<char,unit> = sepBy (pchar ',') (many anyChar)
No 1st-class properties or methods:
let xvalues = points |> Seq.map (fun p -> p.x) let allsplits = filelines |> Seq.map (fun s -> s.Split [| ',' |])
Note that type inference doesn’t work unless the sequence being mapped are to the left of the function wrapping the property or method. There has been a tiny bit of discussion about specific syntax for this, so that something like this would be possible:
let xvalues = points |> Seq.map Point3D#x let allsplits = filelines |> Seq.map (#Split [| ',' |])
So far I like F# quite a bit. It’s really easy to pick up if you already know Haskell and/or O’Caml, and state is convenient at times, especially in an eager language. The semantics are solid. I’m really happy that Microsoft includes F# with Visual Studio now. They’re pushing the idea that the mainstream language doesn’t have to be a over-simplified lowest-common-denominator.
*It’s a perfectly good type system—for an OO type system. For a functional language (Hindley-Milner style), though, an OO type system adds a lot of complexity without giving as much as power as type classes (for example).
**I can’t find it now, but the basic idea is this: make a Num instance that wraps the Continuation monad, storing the “line number” in a map Int -> Continuation. Define a function goto that takes an int and looks up that continuation, calling it. I think. That’s conjecture, because I never saw the code, and I can’t find anything online. I think it was a joke going on the one time I stepped into #haskell.
main = do 100 (putStrLn "Hello World") 200 (goto 100)
The previous entry in this series finished (sort of) the parser. Two things have been hurting my motivation to continue blogging. First is that I needed to blog about the F# version of the parser, since the version I’ve already written about is Haskell. I don’t really want to write about the same thing twice. Second, and more important, is that I was busy working on the actual code instead of blogging about it. There is a decent version online at http://github.com/sandersn/fing. It’s still missing three major features (web app, subtyping and type aliases), but it works for everything in FSharp.Core.
Now I’m at the point of bringing tests up-to-date with the code, so, you guessed it, I have more motivation to blog again. But I still don’t have the gumption to talk about the parser. I’m sick of parsing for now, so maybe I’ll write it up in six months, or when I have time to revamp the core token parser, which is super ugly.
Instead I’m going to write about simple stuff: the command line interface. It’s straightforward, but there is at least one interesting principle in there. I’ll work up to the more complicated parts of the code later.
module Main [<EntryPoint>] let main args = let args,argmap = Opt.parse args let getrefs s = Seq.choose id (Opt.mapGet s argmap Seq.empty) let references = getrefs "r" |>Seq.append<| getrefs "reference" Fing.addReferences references match args with | [| t |] -> Fing.textSearch t | _ -> printfn "Fing is F# API Search. (rest of usage message...)"
There isn’t much surprising here: first I call Opt.parse to produce a list of arguments and keyword arguments. Then I define a function to arguments matching a string s, and use it to build a sequence of “-r” and “–reference” arguments. Well, wait a minute, that’s kind of weird, a nested function. I could have done it this way:
let rs = Seq.choose id (Opt.mapGet s argmap Seq.empty) let references = Seq.choose id (Opt.mapGet s argmap Seq.empty) Fing.addReferences (rs |>Seq.append<| references)
And that’s not bad style, it just isn’t ideal. In the second way, I name the two values, repeating the code that generates them. In the first way, I name the code that generates the two values and repeat only the name I gave it. There’s a little more repetition the second way, with not much benefit.
(I also get a chance to show off the infix-function trick that I discovered. I’m still very proud of that.)
This illustrates one of the subtler aspects of functional programming. The three aspects of functional programming that I think of first are:
Well, ‘functions as data’ looks like a subset of ‘functions everywhere’, but both have a specific meaning. ‘functions as data’ refers to uses of functions that doesn’t occur at all in imperative or OO style: passing them around, saving them in data structures. ‘functions everywhere’ refers to the size and frequency of functions, which is far higher than in imperative or OO styles. Even though the ideal for all styles is many small functions (or methods), functional languages make it natural to achieve this ideal. It is definitely not natural in normal imperative, structured code, and all the “short methods are good for you” advice books indicate to me that it’s not natural in OO either. In any case, if you compare functional languages and OO languages, I think you will find a much greater percentage of the former make short function definition natural.
So, to finish up:
match args with | [| t |] -> Fing.textSearch t | _ -> printfn "Fing is F# API Search. (rest of usage message...)"
There’s not much to say here, except that I am glad pattern matching works on arrays and I wonder why it doesn’t work on sequences. I can think of two reasons: first, seq (aka IEnumerable) is an interface, and pattern matching is a concrete operation. Second, it might be inefficient to pattern match the tail of a sequence. I don’t grok the efficiency model of iterators, but I think that, because they’re not defined recursively, a pattern-match, which treats them as recursive, must create a new enumerator to point to the tail of the matched sequence.
Regardless, it’s an inconvenience and likely one that can be fixed with an active pattern. That’s another F# feature I still need to learn.
Post-script: I had to write Opt.parse myself. I couldn’t find one built-in to .NET. Maybe I was just didn’t search hard enough, but all I found was half-baked code online. I started with one example, intending to translate it to F# in order to understand it. Once I understood it, I saw that it was buggy and incomplete, and wrote my own from scratch. (I just want back, read the comments below the code, and found a link to a reflection/annotation-based library called Consolery. Nothing in the standard library though.
Anyway, continuing with my earlier theme of “I’ll blog about whatever I want to blog about", I’ll probably talk about Opt.parse next. You might be able to help me iron out some of its ugly parts.
It’s about time some changes were made around here.
The first you’ll notice is that the title of this site is no longer Journal, but Blogg. I didn’t like the word ‘blog’ when it was new, but I eventually got used to it. If I’m going to use it, though, it’s going to be the Scandinavian version.
Why Scandinavian? I just finished my doctorate with a dissertation on Swedish dialects. I don’t actually speak Swedish*, but I’ve picked up a little while getting my code to process it. So the change commemorates the fact that I am now (almost) officially Dr Sanders. Or Herr Doktor Sanders, a title bestowed upon students whose advisors are German.
The reason it’s (almost) official is that I have a few revisions to make on the dissertation. When those are done, I’ll upload the final version here. If you really want to see it before then, contact me.
Second, Fing 0.1 is out at github. There’s a binary in case you don’t want to download the source. There’s also a script to load Fing into fsi for interactive use. 0.1 can find functions even if you get the order of arguments wrong. You can also have it search your own assemblies, not just FSharp.Core. But type aliasing doesn’t work right yet, so if you rely on aliases with type variable arguments, you are out of luck until the next version.
The last announcement is that (if you didn’t already know), I’m starting a job at Bing at the beginning of July. Now is a good time to remind everyone that I don’t represent any of my employers, past, present or future, and that this blog is not connected officially or unofficially to Microsoft.
*Jag talar inte Svenska, med jag talar Swedish Chef, darfor vi har de har valdigt har bork bork bork!