F#: how to print full list (Console.WriteLine() prints only first three elements)
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
Nike
Updated on July 09, 2022Comments
-
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 about 14 years
[1;2;3;4;5] |> Seq.iter (printf "%d ")
-- w00t, currying :) -
Tomas Petricek about 14 yearsUnfortunately, 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 about 14 yearsAlso, in recent versions of F#,
List.fold_left
is calledList.fold
and you can replacestring_of_int
with overloadedstring
function. -
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 asSeq.iter
. It of course depends, but in some situations I personally prefer the straightforward (maybe more imperative?) solution. -
abatishchev about 14 yearsIf it's not possible, does it mean that Tomas Petricek's answer is incorrect?
-
TwentyMiles about 14 yearsUpdated to match Tomas's comment. This language has been changing so fast lately, it's a little hard to keep up.
-
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 about 14 yearsYes, 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 about 14 yearsInteresting. Does the pretty-printer function need to be a public member?
-
ssp about 14 years@Joel -- it is unimportant because that property is obtained by refection API
-
MattDavey about 11 years@Juliet actually is not currying, is partial application :)
-
Tahir Hassan over 9 yearsI 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 over 6 years%A doesn't print the whole list:
printf "%A" [1 .. 500];;
stops at100
. -
Tomas Petricek over 6 years@Clément I suspect this might have changed sometime in the last 7 years :-).
-
Clément over 6 yearsI 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 over 6 yearsLooks like you're right. There's always
list |> List.map (sprintf "%A") |> String.concat ", " |> sprintf "[%s]"
then!