1

I have the following error:

Library.fs(86, 40): [FS0193] Type constraint mismatch. The type 'struct (DateTime * Intervals * float * float) option list' is not compatible with type    'Collections.Generic.List<struct (DateTime * Intervals * float * float)>'

The issue is that the F# generates a struct option list and the C# is expecting an IEnumerable with the same types instead.

How can that be converted?

Edit: here is the full error message:

Library.fs(80, 40): [FS0001] The type 'struct (DateTime * Intervals * float * float) option list' is not compatible with the type 'Collections.Generic.List' Library.fs(80, 40): [FS0193] Type constraint mismatch. The type 'struct (DateTime * Intervals * float * float) option list' is not compatible with type 'Collections.Generic.List' Library.fs(81, 16): [FS0001] The type ''a option' does not match the type 'unit'

If I fill the structure with fields I know are not optional, I get the same error:

struct (DateTime.MinValue, Intervals.Tick, 0.0, 0.0)

Screenshot added:

enter image description here

Edit:

I added the ToList() conversion, but it didn't help:

enter image description here

Thomas
  • 10,933
  • 14
  • 65
  • 136
  • On F# side your list contains _optional_ values - i.e. some of them may be missing. What should happen with missing values? – Fyodor Soikin May 16 '19 at 17:51
  • none of the types should be optional in the F# code, they're a date, a C# enum and two floats. – Thomas May 16 '19 at 18:03
  • 2
    Your type is `blah option list` - that means a list of `blah option` values. – Fyodor Soikin May 16 '19 at 18:07
  • I just hardcoded some parameters and the option has disappeared; so I have to track where it comes from. Now even without the option, I need to find how to convert – Thomas May 16 '19 at 18:12
  • Now looks like you need to cast your item to List like described here https://stackoverflow.com/questions/12010316/creating-a-generic-list-t-in-f – Bohdan Stupak May 16 '19 at 18:16
  • You don't need to convert. F# `list` does implement `IEnumerable` – Fyodor Soikin May 16 '19 at 18:17
  • Oh, wait. The error text says "expecting `List`", but your description say that you need to pass `IEnumerable`. So which is it? – Fyodor Soikin May 16 '19 at 18:21
  • Either, since List is part of IEnumerable; I need something I can iterate through on the C# side. – Thomas May 16 '19 at 18:36
  • @Bohdan: I checked that link and it seems to work for simple types, but when I pass the struct as a type for the list, it won't compile – Thomas May 16 '19 at 18:38
  • List is not "part of" IEnumerable. List implements IEnumerable, which means every List is an IEnumerable. But it is not true that every IEnumerable is a List. In fact, if you try to call your C# methods like `f( (IEnumerable<...>) null )`, the compiler will complain, because your method expects a `List` – Fyodor Soikin May 16 '19 at 18:51
  • Sorry, I wrote that the wrong way; what I meant is that any collection I can iterate over is fine :) – Thomas May 17 '19 at 10:10

1 Answers1

3

To create List<T> out of any other enumerable (including F# list) use the .ToList extension method from System.Linq.Enumerable:

open System.Linq
...

db.AddQuotesList(Candle.Intervals.Tick, output.ToList())

Another way is to use one of List's own constructors, which takes an enumerable as argument:

open System.Collections.Generic
...

db.AddQuotesList(Candle.Intervals.Tick, List(output))

Keep in mind, however, that doing this means memory allocation: List is not "lazy" like IEnumerable is, it will allocate a block of memory for all items when you construct it.

Fyodor Soikin
  • 78,590
  • 9
  • 125
  • 172
  • So, maybe the problem is how I generate the list to start with; I'm computing stock market candles and I have the following: let candles = times |> List.map(MakeOneCandle db interval) but this generates an option list; and the ToList() is not available then (I don't know if I mentioned earlier, but this is F# day 2 :)) – Thomas May 16 '19 at 18:59
  • `.ToList` is not available because you haven't opened `System.Linq`. It has nothing to do with `option` – Fyodor Soikin May 16 '19 at 19:36
  • `ResizeArray(output)` uses the F#-specific type abbreviation, if you'd like to have fewer overloads of "list" in the solution. https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/collections.resizearray%5B't%5D-type-abbreviation-%5Bfsharp%5D – Curt Nichols May 16 '19 at 19:42
  • Small function for your library perhaps? ``let toResizeArray l = (ResizeArray (List.length l), l) ||> List.fold (fun a x -> a.Add x; a)`` – dumetrulo May 17 '19 at 07:08
  • @dumetrulo: that doesn't work in this case: Library.fs(87, 53): [FS0001] The type ''a list -> ResizeArray<'a>' is not compatible with the type 'Collections.Generic.List' – Thomas May 17 '19 at 10:12
  • I edited the question with the call to ToList() to show the error. – Thomas May 17 '19 at 10:12
  • @Thomas: How were you trying to use it? I was thinking along the lines of ``db.AddQuotesList(Candle.Intervals.Tick, output |> toResizeArray)``. – dumetrulo May 20 '19 at 10:46
  • I can try that! – Thomas May 20 '19 at 20:30