printf is indeed perplexing, typifying Clarke's third law - 'Any sufficiently advanced technology is indistinguishable from magic.' The secret is contained in source\fsharp\fslib\printf.fs which includes this comment:

1
2
3
    // The general technique used this file is to interpret
    // a format string and use reflection to 'fluff-up' a function value that matches
    // the specification of the format string.  

This method seems to augment the compiler dynamically - in effect compiling the string literal on the fly (i.e. in the type checker.)

Would a strongly typed regex be possible?

1
2
3
4
type cd = {album:string; artist:string}

let getMyCd str   = str |> regex<cd> "cd\=(?<artist>\w+)\:\s(?<album>\w+)"
let getYourCd str = str |> regex<cd> "art\=(?<artist>\w+)\;alb\=(?<album>\w+)"

This begs another question - can this become a common technique used in F#?

Danny

By on 8/19/2008 5:18 PM ()

Thanks Danny but can you explain it simpler. I understood that it is some special case that only applies to printfn but did not understand how it actually works. You mean that reflection is used to modify the compiler itself?

By on 8/20/2008 2:13 AM ()

I seem to remember Don has said a couple of times that using this technique in your own libraries is possible

If I remember correctly, that was a thread about scanf. It might be possible to use printf formats to write a scanf library.

I wrote a blog post about Printf, it might be useful to understand things. You might enjoy some examples, however the article is in french (feel free to ask for a translation).

To understand printf implementation, you can have a look in the source code:

  • formats.ml is used at compile-time. It computes the type from a string format. As far as I know, this is not extensible. Thus, you can't get strong typing with regex or other formats.
  • fslib\printf.fs is used at run-time. It's in the library, thus it is extensible (you could write your own version). It converts the format into string (or whatever type). This library uses reflection to match types computed by the compiler.


I think the best you can get for regex is by using type annotations. Something like:

1
2
let parse input : string * int = regex "([a-z]*) ([0-9]*)" input

This could be an interesting project. To get compiler checks, you'll need to write a compiler patch.

To get a format, you can either use a litteral string where a format is expected (printf "%s"), or add type annotations (let s: Text.Format<_,_,_,_> = "%s%d" - have a look in my blog post for examples).

By on 8/20/2008 2:43 AM ()

I've read through all of the posts in this thread, but I am still not

finding an answer to the original question. By looking at the Printf.fs

file, I'm pretty sure I have a good general understanding of how the

printf family of functions work. I'm still not sure how the string to

TextWriterFormat/Format conversion works, though.

Does anybody know how the compiler is able to convert from a string

literal to a TextWriterFormat? Furthermore, how does it figure out the

correct 'a parameter on TextWriterFormat<'a>? I can't seem to

find where this happens in the F# source, but it's clear that something

interesting needs to happen for the compiler to convert from the string

literal "%d %d" to TextWriterFormat<int -> int -> unit>

when you call printf.

If this happens in the formats.ml file as LLB indicated, I'm missing where it happens.

By on 5/4/2009 1:37 PM ()

Not exactly. Because the type of the first argument is "#TextWriterFormat<'a>" rather than string the compiler generates a function that matches the types of the arguments that are embeded in the string. The type parameter 'a is replaced by this function, meaning the printf function returns a function which looks for the arguments emembed in the format string.

The implmentation of printf is available in F# distrib: source\fsharp\fslib\printf.fs

I just checked and it seemed to compile without problems when copied and pasted into a new F# project so you can have a play with it and see how it works (but obviously this isn't the easiest place to start playing with F#).

Cheers,
Rob

By on 8/20/2008 2:33 AM ()

This begs another question - can this become a common technique used in F#?

I seem to remember Don has said a couple of times that using this technique in your own libraries is possible and can be used to create insteresting libraries, perhaps similar to the above. However, he did say that its quite tricky to do and I have not tried it myself.

Cheers,
Rob

By on 8/20/2008 12:51 AM ()

Last time I checked, the functionality behind the printfn magic wasn't extensible. However, you could probably abuse it to specify types via strings at compile time for purposes other than string formatting. Don't know what that could be useful for.

By on 8/20/2008 1:29 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper