tags:

views:

437

answers:

4

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; ... ]
+2  A: 

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 currying

[1;2;3;4;5] |> Seq.iter (printf "%d ")
JaredPar
`[1;2;3;4;5] |> Seq.iter (printf "%d ")` -- w00t, currying :)
Juliet
`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.
Tomas Petricek
If it's not possible, does it mean that Tomas Petricek's answer is incorrect?
abatishchev
@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.
JaredPar
@Juliet--Sw00t! :-P
Onorio Catenacci
+10  A: 

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).

Tomas Petricek
+1 Didn't know about "%A"
Mehrdad Afshari
A: 

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
TwentyMiles
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
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
Updated to match Tomas's comment. This language has been changing so fast lately, it's a little hard to keep up.
TwentyMiles
@TwentyMiles: 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).
Tomas Petricek
+1  A: 

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 = ()
ssp
Interesting. Does the pretty-printer function need to be a public member?
Joel Mueller
@Joel -- it is unimportant because that property is obtained by refection API
ssp