I'm translating a lot of lisp code right now and find myself using the operand first pipe notation of F#. So instead of the operator first prefix noation of Lisp.

1
(* 25 4 12)

I"m doing this for F#

1
25 |> (*) 4 |> (*) 12

I like the way it always makes the order of operations a left to right affair. The following transformation in why i despise infix notation. We first have to decipher the parenthesis to know where to start reading.

1
25 * (4 + 12)

Written in lisp would be

1
(* 25 (+ 4 12)

And F# becomes

1
4 |> (+) 12 |> (*) 25

So when we rearrange the order of operations infix forces us to rearrange the position of the parenthesis. How many bugs in the history of computer science has this caused?

1
(25 * 4) + 12

With lisp we have to figure out where to start reading based on the postion of the parenthesis as well.

1
(+ (* 25 4) 12) 

But with F# we can always read from left to right

1
25 |> (*) 4 |> (+) 12

I've done the heavy lifting of rearranging the operators and operands but the next programmer won't have to do any work to figure out what's going on. Neat! I'm still undecided on what i prefer. You get pretty used to reading programs "inside out" with Lisp and the following is trivially easy to read and understand.

1
(* 1 2 3 4 5 6 7 8 9)

Not so easy to do this with F#.

By on 9/13/2008 12:16 AM ()

... snip for brevity ...

..with Lisp and the following is trivially easy to read and understand.

1
(* 1 2 3 4 5 6 7 8 9)

Not so easy to do this with F#.

Im not really sure I understand

1
Seq.reduce (*) [1; 2; 3; 4; 5; 6; 7; 8; 9]

Sure it's a bit wordier and I can sure appriciate the beauty of the Lisp way but it not that horrible.

By on 9/16/2008 7:27 AM ()

I agree, explicitly declaring a sequence and calling reduce is not a big deal. On a side note, what is the difference between the reduce and fold functions in F#?

1
Seq.fold (*) 1 [2; 3; 4; 5; 6; 7; 8; 9]

does basically the same thing, apply and accumulate. Is one preferred to the other?

By on 9/16/2008 6:34 PM ()

They are similar, but fold is more general. reduce assumes that the output type is the same as the type of elements in the input, and assumes the sequence contains at least one element. So in the examples below, the first two can be expressed either way, whereas the last two can only be done with folds.

1
2
3
4
5
6
printfn "%d" (List.reduce_left (+) [1;2;3])
printfn "%d" (List.fold_left (+) 1 [2;3])

printfn "%s" (List.fold_left (fun s x -> s + x.ToString()) "" [1;2;3])
printfn "%s" (List.fold_left (fun s x -> s + x.ToString()) "" [])

In general I would say "use reduce when possible, and fold when necessary".

By on 9/16/2008 7:14 PM ()

Hi,

This difference here is that Lisp has variadic functions (functions can have a variable number of arguments). F# doesn't have this feature, because it has type inference and partial application (if some arguments are missing, it returns a new function). Thus, this will never be allowed in F#: (+) 1 2 3. (+) expects two arguments. If you redefine (+) so that it returns a function, then 3 is used as an argument to the returned function. This behavior is indeed quite different from Lisp.

You might prefer this notation:

1
2
3
let inline (+.) n = Seq.sum n
let ( *. ) n = Seq.reduce (*) n
(+.) [( *.) [25; 4]; 12]

Or this one:

1
2
3
let (!!) = Seq.reduce

!!(+) [!!(*) [25; 4]; 12]

But I think this is not very readable (it looks strange for a F# developer), and I recommend you to use the infix notation. If you think it's confusing when moving expressions, why not using more local bindings?

1
2
3
let x = 24 * 4

x + 12
By on 9/13/2008 3:07 AM ()

Thanks for the explanation LLB. I agree the simulated postfix notation you present would be hard for an F# developer to decipher. Creative none the less.

I can see how F#'s use of lists mitigates the need for variadic functions. Not sure why type inference prevents variadic function. I can see how partial application poses a problem, do you return the result of the function or a new residue function?. Perhaps there could be some notation for this, let vs letf.

By on 9/14/2008 8:42 AM ()

Hello,

I think the problem here is that F# statically typed were as lisp is dynamic, which leads to a number of difference in the way you'd approach problems.

The * operator in F# only takes two operands and unless you choose to explicitly redefine it this will always be the case. In fact to me, who is unfamilar with LISP, it seems a little crazy that an operator could be applied to 2 or 3 operands, although I can see it a powerful notition to have in language.

If the amount of operators you want to work with is know statically, and thanks to F# static type system it generally is, then I'd just put the operators inbetween.

1
let res = 25 * 4 * 12

If the number of operators varies in length then you must represent this as a list (or other collection type). In so in this case you'd use high order functions to work with your list:

1
let res = Seq.reduce ( * ) [ 25; 4; 12]

Yes, the |> operator is used quite a bit in F# programming but not really in the context you are using it. It's more used when you want to avoid typing an extra "let" binding.

Cheers,
Rob

By on 9/13/2008 12:13 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper