2
votes

For the sake of using literate programming (i.e. cweb) in F#, I need to be able to forward declare functions (i.e. use them before defining them). I came up with two ways, both of them unpleasing. Can you think of something better (easier to use for the programmer)?

Nice, but doesn't work with polymorphic functions

// This can be ugly
let declare<'a>  = ref Unchecked.defaultof<'a>

// This has to be beautiful
let add = declare<float -> float>

let ``function I want to explain that depends on add`` nums = nums |> Seq.map !add

add := fun x -> x + 1.

Ugly, but works with everything

// This can be ugly
type Literate() =
static member Declare<'a, 'b>  (ref : obj ref) (x : 'a) : 'b =
                                    unbox <| (unbox<obj -> obj> !ref)
static member Define<'a, 'b> (func : 'a -> 'b) (ref : obj ref) (f : 'a -> 'b) =
                                    ref := box (unbox<'a> >> f >> box)

// This has to be beautiful
let rec id (x : 'a) : 'a = Literate.Declare idImpl x
and idImpl = ref null

let f () = id 100 + id 200

Literate.Define id idImpl (fun x -> x)
4
That is anti-idiomatic. Are you sure you cannot document the way you program? - Ramon Snir
The reasons for this requirement are worth a post on its own (upcoming), for now let's try to solve the puzzle if there is a better way to do forward function declaration. - user965221

4 Answers

3
votes

I used a tool that follows the same ideas as literate programming when creating www.tryjoinads.org. A document is simply a Markdown with code snippets that get turned into an F# source code that you can run and the snippets have to be in a correct order. (In some literate programming tools, the documentation is written in commments, but the idea is the same.)

Now, I think that making your code more complicated so that you can write it in a literate programming style (and document it) is introducing a lot of accidental complexity and it is defeating the main purpose of literate programming.

So, if I wanted to solve this problem, I would extend my literate programming tool with some annotation that specifies the order of code blocks that is needed to make the script work (and a simple pre-processing tool can re-order them when generating F# input). You can take a [look at my build script][1] for TryJoinads, which would be fairly easy to extend to do this.

The tool I used for TryJoinads already provides some meta-tags that can be used to hide code blocks from the output, so you can write something like:

## This is my page heading

    [hide]
    // This function will be hidden from the generated HTML
    // but it is visible to the F# compiler
    let add a b = a + b 

Here is the description for the other function:

   let functionThatUsesAdd x = add x x

And later on I can repeat `add` with more comments (and I can add an annotation
`module` to avoid conflicts with the previous declaration):

   [module=Demo]
   let add a b =
     // Add a and b
     a + b

This also isn't perfect, because you have to duplicate functions, but at least your generated blog post or HTML documentation will not be obscured by things that do not matter. But of course, adding some meta-command like module or hide to specify order of blocks wouldn't be too hard and it would be a clean solution.

In summary, I think you just need a better literate programming tool, not different F# code or F# langauge.

1
votes

Perhaps I'm missing something, but why aren't you going all the way and 'doing it properly'?

Using the function first:

<<test.fs>>=
<<add>>
let inc = add 1

Declaring the function afterwards:

<<add>>=
let add a b = a + b
0
votes

Since functions are first-class objects in F#, you can pass them around instead -- which presents a much nicer (and still immutable) solution than forward references.

let dependentFunction f nums = nums |> Seq.map f

let ``function I want to explain that depends on add`` nums =
    dependentFunction (fun x -> x + 1.) nums

Also, in most cases you should be able to use currying (partial function application) to simplify the code further but the type inference for seq<'T> is a little strange in F# because it's usually used as a flexible type (similar to covariance in C# 4.0). To illustrate:

// This doesn't work because of type inference on seq<'T>,
// but it should work with most other types.
let ``function I want to explain that depends on add`` =
    dependentFunction (fun x -> x + 1.)

Finally, a good rule of thumb for using ref or mutable in F# is that if you're only going to assign the value once (to initialize it), there's probably a cleaner, more functional way to write that code (passing the value as a function parameter (as above) and lazy are two such approaches). Obviously there are exceptions to this rule, but even then they should be used very sparingly.

0
votes

As I said, this is wrong (and you should publish a blog article, or a FPish post, about why you're doing this)), but here is my take:

let ``function I want to explain that depends on add``
      (add : float -> float) = nums |> Seq.map add

let add = (+) 1.

let ``function I want to explain that depends on add`` = ``function I want to explain that depends on add`` add