When calling Seq.zip and then feeding the result into printfn "%A", the output is not correctly formatted.
When running the sample:
// ...
printfn "%A" (Seq.zip x y) // produces: [object Object]
printfn "%A" (List.toSeq (Seq.toList <| Seq.zip x y)) // produces: [1,5; 2,6; 3,7]
we can see that Seq.zip by itself produces something not quite right behind the scenes, but converting to a List and back corrects the problem.
dotnet fable --version): REPL2 (Version: 2.0.11)Probably that happens because of the use of Seq.map2. Seq.map and Seq.map3 give the same result.
Another thing I forgot to include in the example that sheds some light on the underlying representation:
If you use Fable.Import.JS.console.log which will show up in the browser console (instead of just the REPL output), which lets you inspect the actual JS objects, you can see that Seq.zip represents the sequence as an iterator object (which I'm guessing printfn doesn't know how to deal with correctly), but when you convert to a List and back, the sequence keeps the underlying List, since there is no need to coerce it back to an iterator:
Fable.Import.JS.console.log(Seq.zip x y):
{Symbol(Symbol.iterator): 茠}
Symbol(Symbol.iterator): () => f()[Symbol.iterator]()
__proto__: Object
Fable.Import.JS.console.log(List.toSeq (Seq.toList <| Seq.zip x y)):
List {head: Array(2), tail: List}
head: (2) [1, 5]
tail: List {head: Array(2), tail: List}
__proto__: Object
It seems like the real issue is that printfn doesn't properly deal with a Seq when its represented by an iterator in the underlying JS.
printfn "%A" wasn't implemented very consistently and it started to give problems when we added decimal support, so I disabled it and now %A and %O produce the same output: basically just converting to string. Lists and other basic types implement toString so when converting we get a good format, but this is not the case for lazy sequences.
I can think of three possible solutions for this:
%A and implement them. I'm not sure if I'll have time to do it, but it may be nice to have a PR.%A detect if the element is an iterable which doesn't implement toString and then compute the first items for the formatting.toString. This can make them compatible also with other tools, but it won't work for iterables coming from a JS library.The last one seems like the most robust solution to me, though I couldn't say whether or not it would make sense in the context of how Fable juggles types and performance in the back-end.
Ultimately, this problem is only a minor annoyance in my opinion. While Fable is F#, it is still running on JavaScript which definitely needs to be considered by the programmer at times. I'd say this is a reasonable difference between F# on other platforms, and F# on JavaScript, especially since it only involves printing and formatting, which is more a "nice to have" than a necessary feature (a lot of modern languages won't print data structures out of the box either, for instance).
Closing for now, please feel free to reopen if someone wants to send a PR for this.