Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't you write "(::) 1 [2]" the way you can write "(+) 1 2" in F#?

Tags:

f#

Put an F# infix operator in brackets, and it behaves like a function,

let foo = (*) 3 2  // foo = 6
let factorial n = [2..n] |> List.fold (*) 1  // n!

However, this doesn't work with the :: operator (cons operator),

let ls = (::) 1 [2..5]  // Error: Unexpected symbol '::' in binding.

What's the reason for this?

like image 707
John Reynolds Avatar asked Aug 25 '14 21:08

John Reynolds


2 Answers

You can use the static method:

let ls = List.Cons (1, [2..5])

or the operator's verbose name:

let ls = op_ColonColon (1, [2..5])

(checked with F# 3.0; older versions may behave differently. For instance, MSDN suggests op_Cons)

In both cases, there's no way to curry the arguments here. Numeric operators are defined like this:

let inline ( * ) (x:int) (y:int) = ...

The list concatenation, however, requires a tuple, and this also answers your question,

What's the reason for this?

In fact, (::) is not an usual operator (a standalone function or a type member), but a union case. Here's how the List<'T> is defined in F# sources:

type List<'T> =
    | ([])  : 'T list
    | (::)  : Head: 'T * Tail: 'T list -> 'T list

So, if your purpose is partial application of arguments, the only nice solution would be writing a wrapper function as @pad has suggested.

like image 119
bytebuster Avatar answered Sep 19 '22 16:09

bytebuster


Because (::) (and [] for that matter) is a symbolic keyword, you can't expect to use it as an infix operator. See F# specification, section 3.6 Symbolic keywords.

In this case, you have to define an extra function e.g.

let cons x xs = x :: xs
let ls = cons 1 [2..5]
like image 23
pad Avatar answered Sep 18 '22 16:09

pad