Skip to content

Instantly share code, notes, and snippets.

@ForNeVeR
Last active November 30, 2023 09:48
Show Gist options
  • Save ForNeVeR/135addb5c95faaba80e8a122dcaf7392 to your computer and use it in GitHub Desktop.
Save ForNeVeR/135addb5c95faaba80e8a122dcaf7392 to your computer and use it in GitHub Desktop.
open System
let mutable debug = true
type T = T with
static member inline ($) (T, arg: unit) = ()
static member inline ($) (T, arg: int) = 0 // mandatory second terminal case; is unused in runtime but is required for the code to compile
static member inline ($) (T, func: ^a -> ^b): ^a -> ^b =
fun (_: 'a) -> T $ Unchecked.defaultof<'b>
let inline negate(): 'a =
T $ Unchecked.defaultof<'a>
let inline debugLog format =
if debug then
Printf.kprintf (
printfn "%A: %s" DateTime.Now
) format
else negate()
[<EntryPoint>]
let main _ =
debug <- false
debugLog "This: %s" "foo"
debugLog "That: %d - %d = %d" 2 2 4
debugLog "Invisible! %s" "haha"
debug <- true
debugLog "Visible"
0
@habib-sadullaev
Copy link

You said function, not method. So ParamArray is not an option.

The Haskell code you linked is based on the inferred result type.

Here's a way to resolve based on the inferred result type in F#:

type T = T with
    static member inline ($) (T, r:'t->'t        ) = fun a b     -> a + b
    static member inline ($) (T, r:'t->'t->'t    ) = fun a b c   -> a + b + c
    static member inline ($) (T, r:'t->'t->'t->'t) = fun a b c d -> a + b + c + d

let inline sum (x:'a) :'r = (T $ Unchecked.defaultof<'r>) x

let x:int = sum 2 3 
let y:int = sum 2 3 4
let z:int = sum 2 3 4 5
let d:decimal = sum 2M 3M 4M

let mult3Numbers a b c = a * b * c
let res2 = mult3Numbers 3 (sum 3 4  ) 10
let res3 = mult3Numbers 3 (sum 3 4 5) 10

UPDATE

The above code doesn't work anymore as from F# 4.1 (see the comments) but here's a better example with a recursive polyvariadic function taking n (unlimited) arguments:

type T = T with
    static member        ($) (T, _:int    ) = (+)
    static member        ($) (T, _:decimal) = (+)

let inline sum (i:'a) (x:'a) :'r = (T $ Unchecked.defaultof<'r>) i x

type T with
    static member inline ($) (T, _:'t-> 'rest) = fun (a:'t) -> (+) a >> sum


let x:int = sum 2 3 
let y:int = sum 2 3 4
let z:int = sum 2 3 4 5
let d:decimal = sum 2M 3M 4M

let mult3Numbers a b c = a * b * c
let res2 = mult3Numbers 3 (sum 3 4) (sum 2 2 3 3)
let res3 = mult3Numbers 3 (sum 3 4 5 11 13 20) 10

You can also have a look at this polyvariadic fold.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment