trent-AZ
trent-AZ

Reputation: 61

How to format a multi-line F# function in VisualStudio *.fsx

Q1: I want to format an F# function over multiple lines in *.fsx in Visual Studio 2019, but when I try, I get syntax errors. (See below.)

Q2: In Haskell (as I recall) the order in which you declare functions doesn't matter. Is the same true in F#?

(* 
2.3 Declare the F# function 
isIthChar: string * int * char -> bool 
where the value of isIthChar(str,i,ch) is true 
if and only if ch is the i’th character in the string str 
(numbering starting at zero).

Hansen, Michael R.. Functional Programming Using F# (p. 39). Cambridge University Press. Kindle Edition. *)

let isIthChar (str: string, i, ch) = (ch = str.[i])

(* 
2.4 Declare the F# function 
occFromIth: string * int * char -> int where 

occFromIth(str, i, ch) = 
    the number of occurances of character ch
        in positions j in the string str
        with j >= i

Hint: the value should be 0 for i ≥ size str.

Hansen, Michael R.. Functional Programming Using F# (p. 39). Cambridge University Press. Kindle Edition. 
*)

let rec countChar(str, i, j, ch, cnt) = if j < i then cnt else if isIthChar(str, j, ch) then countChar(str, i, j - 1, ch, cnt + 1) else countChar(str, i, j - 1, ch, cnt);; // all one line


let occFromIth(str, i, ch) = if (i >= String.length str) then 0 else countChar(str, i, (String.length str) - 1, ch, 0);; // all one line


//WANT something like:

let rec countChar(str, i, j, ch, cnt) = if j < i 
    then cnt 
    else if isIthChar(str, j, ch) 
    then countChar(str, i, j - 1, ch, cnt + 1) 
    else countChar(str, i, j - 1, ch, cnt);;

let occFromIth(str, i, ch) = if (i >= String.length str) 
    then 0 
    else countChar(str, i, (String.length str) - 1, ch, 0);;

// but these give syntax errors.


(* 2.5 Declare the F# function occInString: string * char -> int where

occInString(str, ch) = the number of occurences of a character ch in the string str.

Hansen, Michael R.. Functional Programming Using F# (p. 39). Cambridge University Press. Kindle Edition. *)

let occInString(str, ch) = occFromIth(str, 0, ch)

Upvotes: 2

Views: 408

Answers (1)

Fyodor Soikin
Fyodor Soikin

Reputation: 80744

Formatting: then and else must be at least as far to the right as their preceding if, but in both your cases they're way to the left of it. Just move the if on the next line:

let rec countChar(str, i, j, ch, cnt) = 
    if j < i 
    then cnt 
    else if isIthChar(str, j, ch) 
    then countChar(str, i, j - 1, ch, cnt + 1) 
    else countChar(str, i, j - 1, ch, cnt)

Also note that double-semicolon is not necessary if the code is in an fsx file as opposed to being typed into FSI from keyboard.


Order of declaration: unlike Haskell, in F# all names must be defined before they're used, so your program reads top to bottom. This may seem limiting at first, but in practice it does wonders for code readability.

An exception to this rule is a group of mutually recursive functions (or types):

let rec f x = g (x+1)
and g x = f (x-1)

In this example g is used before it's defined.

Recently F# also got recursive modules, inside which all definitions are considered to be one large recursive group:

module rec A =
  let f x = g (x+1)
  let g x = f (x-1)

A few notes not strictly related to your questions:

  • else if can be abbreviated elif
  • While it's possible to define parameters as a tuple countChar(str, i, j, ch, cnt), it is customary (and vastly more convenient in practice) to define them in curried form countChar str i j ch cnt

Upvotes: 2

Related Questions