I did the Advent of Code to learn F#

I documented my struggles in

Please, copy text here. It is don’t open from me.

I think it is good idea while without return, break and continue. One flow, no surprise jumping. Guard condition enough. Simplify one big function via composition many small functions.

For example count sub arrays sum elements equals 5:

let xs = [|7; 2; -5; 1; 1; -1; 5; -5|] 
let k = 5

let count_ranges xs k = 
    let mutable r = 0
    let mutable s = 0

    let max = (Array.length xs) - 1

    for i = 0 to max do
        s <- 0
        for j = i to max do
            s <- s + xs.[j]
            if s = k then r <- r + 1 

    s // return from count_ranges


count_ranges xs k |> printfn "%d"

In the IronScheme analog (more low level and total immutable):

(define xs '(7 2 -5 1 1 -1 5 -5))
(define k 5)
; найти количество диапазанов из xs сумма которых равна k

(define (rest xs)
    (if (null? xs) '() (cdr xs)))

(define (sublist lst start end)
    (define (rotor i ls acc s e)
         (if (<= i e)
             (rotor (+ i 1) (rest ls) (if (or (< i  s) (null? ls))
                                         acc 
                                        (cons (car ls) acc)) s e)
             acc))
    (reverse 
        (rotor 0 lst '() start end)))   

(define (sum-list xs)
    (define (loop ys acc)
        (if (null? ys) 
            acc 
            (loop (cdr ys) (+ acc (car ys)))))
    (loop xs 0))

(define (count-ranges xs k)
  (define (count-helper start end)
    (writeln (list start end))
    (if (>= start (length xs))
        0
        (if (>= end (length xs))
            (count-helper (+ start 1) (+ start 1)) ; Переход к следующему началу
            (let ((current-sum (sum-list (sublist xs start end))))
              (+ (if (= current-sum k) 1 0)
                 (count-helper start (+ end 1)))))))
  (count-helper 0 1))

(count-ranges xs k)

Nice article!

You present 2 quite good arguments/reasons for why functional programming languages are harder to get into.

I remember, when I first got into FP, I also missed the early return (and break and continue ofc).
I don’t think you mention it in the article, but from my understanding, the reason for why reaturn, break and continue are not in F# is not because of mutability, but because they are statements. In F# everything is an expression (have a return value, which can be unit () if there is no value to return). For example, in C# we have if-statements but in F# we have if-expressions.

To have everything as an expression comes with some drawbacks, but I also think those are outweighed by the benefits, especially as a program gets larger and more complex.

I don’t remember where heard it, but I think there is some truth to the statement: “Functional programming makes easy things hard, and hard things easy”. :wink:

I totally agree on the error messages though :sweat_smile:
But there are some functional programming languages, like Gleam, which has great error messages!