Search code examples
functionf#memoizationidiomsunit-type

When to add a unit argument to an existing function in F#


If I am already passing other parameters into a function, do I have any reason to pass in a unit argument as well, assuming the function is non-deterministic? Do I need to worry about memoization repeating return values? Are there any aspects of style or idiom to consider in this case?


Solution

  • If you already have a function that takes some arguments, but also happens to have some side-effects and be non-deterministic, then I would not expect the function to take an additional unit parameter. For example, a randomPoint function would just take maxX and maxY but not additional unit:

    let rnd = System.Random()
    
    // Normal way of writing this
    let randomPoint maxX maxY = 
      rnd.Next(maxX), rnd.Next(maxY)
    
    let pt1 = randomPoint 100 200
    
    // You can do this, but it is not usual style
    let randomPoint maxX maxY () = 
      rnd.Next(maxX), rnd.Next(maxY)
    
    let pt2 = randomPoint 100 200 ()
    

    There are some cases where an extra unit parameter may be helpful, but this is only the case when you want to create a function to be called later. For example:

    let makePointGenerator maxX maxY = 
      let rnd = System.Random()
      fun () -> rnd.Next(maxX), rnd.Next(maxY)
    
    // This should be used as follows
    let gen = makePointGenerator 100 200
    let pt1 = gen () 
    let pt2 = gen ()
    
    // You can call it like this, but it is not the intention
    let pt3 = makePointGenerator 100 200 ()
    

    Something like this may occasionally be useful for memoization - but this is not something that ever happens automatically and so if you find yourself writing code that requires this, you will know.