The function argument is null, although a non-empty argument is passed

F # is new here and sorry for the bad title, I'm not sure how else to describe it.
I have a very strange problem. Here is the relevant code snippet:

let calcRelTime (item :(string * string * string)) = tSnd item |>DateTime.Parse |> fun x -> DateTime.Now - x |> fun y -> (floor y.TotalMinutes).ToString() |>makeTriple (tFst item) (tTrd item) //makeTriple switches y & z. How do I avoid having to do that? let rec getRelativeTime f (l :(string * string * string) list) = match l with | [] -> f | x :: xs -> getRelativeTime (List.append [calcRelTime x] f) xs 

I am viewing it with Visual Studio, and it clearly shows that x in getRelativeTime is a 3-tuple with a well-formed datetime string. But when I go to calcRelTime, item is null. It all ends up returning a 3-tuple that has the original date and time string, and not one with the past minutes. There are no other errors anywhere until this datetime string hits a function that expects it to be a whole string.

Any help would be appreciated! (along with any other F # style tips / suggestions for these functions).

0
source share
2 answers

item is null since it has not yet been created from its parts. The F # compiler compiles the parameters as separate actual (IL-level) parameters, and not a single parameter of type Tuple<...> . If you look at your compiled code in ILSpy, you will see this signature (using C # syntax):

 public static Tuple<string, string, string> calcRelTime(string item_0, string item_1, string item_2) 

This is done for several reasons, including compatibility with other CLR languages, as well as efficiency.

Of course, the tuple itself is then built from these arguments (unless you have turned on optimization), but not immediately. If you take one step (press F11), item will get the correct non-zero value.

You can also see these parameters generated by the compiler if you go to Debug -> Windows -> Locals in Visual Studio.

As for why it returns the original list instead of the changed one, I cannot say: in my setup, everything works as expected:

 > getRelativeTime [] [("x","05/01/2015","y")] val it : (string * string * string) list = [("x", "y", "17305")] 

Perhaps if you share your test code, I can tell you more.

And finally, what you do can be made much simpler: you donโ€™t need to write a recursive loop yourself, itโ€™s already done for you in many functions of the List module, and you donโ€™t know, you need to take a tuple and then deconstruct it with Using tFst , tSnd and tTrd , the compiler can do this for you:

 let getRelativeTime lst = let calcRelTime (x, time, y) = let parsed = DateTime.Parse time let since = DateTime.Now - parsed let asStr = (floor since.TotalMinutes).ToString() (x, asStr, y) List.map calRelTime lst 
+1
source
 let getRelativeTime' list = let calc (a, b, c) = (a, c, (floor (DateTime.Now - (DateTime.Parse b)).TotalMinutes).ToString()) list |> List.map calc 

Signature of the function val getRelativeTime : list:('a * string * 'b) list -> ('a * 'b * string) list

You can deconstruct item in function declaration to (a, b, c) , then you do not need to use tFst , tSnd and tTrd .

The List module has a map function that applies a function to each item in the list and returns a new list with the displayed values.

+1
source

All Articles