Hasan A Yousef
Hasan A Yousef

Reputation: 25008

The result of this expression is implicitly ignored. Consider using 'ignore' e.g. 'expr |> ignore', or ' e.g. 'let result = expr'

I'm trying to build F# equivalent code for the Python code appearing here, I've the below code:

let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
    let result : float list = []
    let mutable smooth = 0.
    let mutable trend = 0.
    let seasonals = initialSeasonalComponents series 12
    for i in 0..(series.Length+nPreds-1) do
    match i with
    | 0 ->     // initial values        
        smooth <- series |> Array.head |> float
        trend <- initialTrend series slen
        result |> List.append [series |> Array.head |> float] |> ignore
    | i when i >= series.Length -> // we are forecasting
        let m = i - series.Length + 1
        result |> List.append [(smooth + float m * trend) + seasonals.Item(i%slen)] |> ignore
    | _ -> 
        let v = series |> Array.head  |> float
        let lastSmooth = smooth
        smooth <- alpha*(v-seasonals.Item(i%slen)) + (1.-alpha)*(smooth+trend)
        trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
        seasonals.Item(i%slen) <- gamma*(v-smooth) + (1.-gamma)*seasonals.Item(i%slen)
        result |> List.append [smooth + trend + seasonals.Item(i%slen)] |> ignore
    result

For which I got the below error:

warning FS0020: The result of this expression is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr'.

I tried to write the above as conversion of the below Python code:

def triple_exponential_smoothing(series, slen, alpha, beta, gamma, n_preds):
    result = []
    seasonals = initial_seasonal_components(series, slen)
    for i in range(len(series)+n_preds):
        if i == 0: # initial values
            smooth = series[0]
            trend = initial_trend(series, slen)
            result.append(series[0])
            continue
        if i >= len(series): # we are forecasting
            m = i - len(series) + 1
            result.append((smooth + m*trend) + seasonals[i%slen])
        else:
            val = series[i]
            last_smooth, smooth = smooth, alpha*(val-seasonals[i%slen]) + (1-alpha)*(smooth+trend)
            trend = beta * (smooth-last_smooth) + (1-beta)*trend
            seasonals[i%slen] = gamma*(val-smooth) + (1-gamma)*seasonals[i%slen]
            result.append(smooth+trend+seasonals[i%slen])
    return result

What the wrong things I did, and what is the correct code equivalent to the mentioned Python's one.

Upvotes: 1

Views: 2625

Answers (2)

Gus
Gus

Reputation: 26204

You are running the for as a side effect.

Maybe you want to a seq expression, I think in Python you have generators but here in F# remember that everything is an expression.

let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
    let mutable smooth = 0.
    let mutable trend = 0.
    let seasonals = initialSeasonalComponents series 12 |> Dictionary 
    seq {
        for i in 0..(series.Length+nPreds-1) do
          match i with
          | 0 ->     // initial values        
              smooth <- series |> Array.head |> float
              trend <- initialTrend series slen
              yield series |> Array.head |> float
          | i when i >= series.Length -> // we are forecasting
              let m = i - series.Length + 1
              yield (smooth + float m * trend) + seasonals.[i%slen]
          | _ -> 
              let v = series |> Array.head  |> float
              let lastSmooth = smooth
              smooth <- alpha*(v-seasonals.[i%slen]) + (1.-alpha)*(smooth+trend)
              trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
              seasonals.[i%slen] <- gamma*(v-smooth) + (1.-gamma)*seasonals.[i%slen]
              yield smooth + trend + seasonals.[i%slen] }

So, a sequence expressions is of the form seq { expr } and inside the expression you use yield to yield results.

Upvotes: 4

Tomas Petricek
Tomas Petricek

Reputation: 243126

As mentioned in the other answer, you are trying to mutate the list of results in the for loop, but this is not possible, because F# lists are immutable by default.

If you want to directly follow the style of the Python code, you can use mutable ResizeArray:

let tripleExponentialSmoothing series slen alpha beta gamma nPreds =
    let result = ResizeArray<_>()
    let mutable smooth = 0.
    let mutable trend = 0.
    let seasonals = initialSeasonalComponents series 12
    for i in 0..(series.Length+nPreds-1) do
      match i with
      | 0 ->     // initial values        
          smooth <- series |> Array.head |> float
          trend <- initialTrend series slen
          result.Add(series |> Array.head |> float)
      | i when i >= series.Length -> // we are forecasting
          let m = i - series.Length + 1
          result.Add((smooth + float m * trend) + seasonals.Item(i%slen))
      | _ -> 
          let v = series |> Array.head  |> float
          let lastSmooth = smooth
          smooth <- alpha*(v-seasonals.Item(i%slen)) + (1.-alpha)*(smooth+trend)
          trend <- beta * (smooth-lastSmooth) + (1.-beta)*trend
          seasonals.Item(i%slen) <- gamma*(v-smooth) + (1.-gamma)*seasonals.Item(i%slen)
          result.Add(smooth + trend + seasonals.Item(i%slen))

This is not very idiomatic F# code, but it solves your immediate problem. For a more functional solution, you can go with sequence expressions as mentioned by Gustavo and yield results one by one, but you still keep smooth and trend as mutable variables, so there probably is even nicer way of doing this - but that's hard to guess without knowing more about your algorithm.

Upvotes: 2

Related Questions