F#: how to print full list (Console.WriteLine() prints only first three elements)

32,798

Solution 1

If you want to use the built-in F# formatting engine (and avoid implementing the same thing yourself), you can use F# printing functions such as printfn. You can give it a format specifier to print an entire list (using F# formatting) or print just a first few elements (which happens when you call ToString):

> printfn "%A" [ 1 .. 5 ];;  // Full list using F# formatting 
[1; 2; 3; 4; 5]

> printfn "%O" [ 1 .. 5 ];;  // Using ToString (same as WriteLine)
[1; 2; 3; ... ]

If you want to use Console.WriteLine (or other .NET method) for some reason, you can also use sprintf which behaves similarly to printf, but returns the formatted string as the result:

Console.WriteLine(sprintf "%A" list)

The benefit of using printf or sprintf is that it also automatically deals with other F# types (for example if you have a list containing tuples, discriminated unions or records).

Solution 2

No it's not possible to print the contents of an F# list without using a cycle / loop of sorts. To print every element you must enumerate each of them.

In F# though it doesn't need to be done with a loop though but instead can be done with a nice pipe operation

[1;2;3;4;5] |> Seq.iter (fun x -> printf "%d " x)

And as Juliet pointed out I could simplify this further with partial application

[1;2;3;4;5] |> Seq.iter (printf "%d ")

Solution 3

In general, if you want to change as a way an printf "%A" prints your objects as a way fsi.exe shows values fo your type, you can apply StructuredFormatDisplayAttribute attribute to your type:

[<StructuredFormatDisplayAttribute("PP {PrettyPrinter}")>]
type Foo(a:string array) =
  let pp = Array.mapi (fun i (s: string) -> sprintf "{idx: %d len: %d contents: '%s'}" i s.Length s) a
  member x.PrettyPrinter = pp

> let foo = Foo [|"one";"two";"three"|];;
val foo : Foo =
  PP [|"{idx: 0 len: 3 contents: 'one'}"; "{idx: 1 len: 3 contents: 'two'}";
       "{idx: 2 len: 5 contents: 'three'}"|]

> printfn "%A" foo;;
PP [|"{idx: 0 len: 3 contents: 'one'}"; "{idx: 1 len: 3 contents: 'two'}";
     "{idx: 2 len: 5 contents: 'three'}"|]
val it : unit = ()

Solution 4

A perhaps more functional way of doing it:

let nums = [1;2;3;4;5;6]
let concat acc x = acc + " " + (string x)
let full_list = List.fold concat "" nums
printfn "%s" full_list
Share:
32,798
Nike
Author by

Nike

Updated on July 09, 2022

Comments

  • Nike
    Nike almost 2 years

    Is it possible to print full list without using cycle? I tried:

    Console.WriteLine([1;2;3;4;5])
    

    and it prints only three first elements:

    [1;2;3; ... ]
    
  • Juliet
    Juliet about 14 years
    [1;2;3;4;5] |> Seq.iter (printf "%d ") -- w00t, currying :)
  • Tomas Petricek
    Tomas Petricek about 14 years
    Unfortunately, string concatenation is very inefficient operation on .NET (because it needs to copy the entire string), so this may have bad performance for large lists. In .NET, the recommended way would be to use StringBuilder (which is mutable and makes the solution a bit less functional).
  • Tomas Petricek
    Tomas Petricek about 14 years
    Also, in recent versions of F#, List.fold_left is called List.fold and you can replace string_of_int with overloaded string function.
  • Tomas Petricek
    Tomas Petricek about 14 years
    for x in [1;2;3;4;5] do printf "%d " x - I actually think simple for loop would be just as good as Seq.iter. It of course depends, but in some situations I personally prefer the straightforward (maybe more imperative?) solution.
  • abatishchev
    abatishchev about 14 years
    If it's not possible, does it mean that Tomas Petricek's answer is incorrect?
  • TwentyMiles
    TwentyMiles about 14 years
    Updated to match Tomas's comment. This language has been changing so fast lately, it's a little hard to keep up.
  • JaredPar
    JaredPar about 14 years
    @abatischev, @Tomas's answer is certainly correct and functional but under the hood a loop is occurring to print out the elements it's just not in the actual answer code.
  • Tomas Petricek
    Tomas Petricek about 14 years
    Yes, especially the naming! However, now that F# is a part of Visual Studio 2010 (which is almost finished), there won't be that many changes (in the language and core libraries).
  • Joel Mueller
    Joel Mueller about 14 years
    Interesting. Does the pretty-printer function need to be a public member?
  • ssp
    ssp about 14 years
    @Joel -- it is unimportant because that property is obtained by refection API
  • MattDavey
    MattDavey about 11 years
    @Juliet actually is not currying, is partial application :)
  • Tahir Hassan
    Tahir Hassan over 9 years
    I noticed that "%A" with a seq<'a> will not print only a few elements (then ellipses). I used Seq.toList to convert it to a list.
  • Clément
    Clément over 6 years
    %A doesn't print the whole list: printf "%A" [1 .. 500];; stops at 100.
  • Tomas Petricek
    Tomas Petricek over 6 years
    @Clément I suspect this might have changed sometime in the last 7 years :-).
  • Clément
    Clément over 6 years
    I don't think so :) AFAICT, it was already wrong back in 2009 (see e.g. stackoverflow.com/questions/1656200/… , which mentions the issue).
  • Tomas Petricek
    Tomas Petricek over 6 years
    Looks like you're right. There's always list |> List.map (sprintf "%A") |> String.concat ", " |> sprintf "[%s]" then!