Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement "return early" logic in F#

I am familiar with the fact that in F# there is no equivalent "return" keyword.

However we came across an issue recently where we have needed a workflow that consists of many steps, where each step can return a good or bad result. If a bad result is found in any of the steps, we wanted to exit the workflow - and exit early!

We got around it by effectively checking for an Error in each step (i.e. function) but I dont feel that this is the correct way to do it - it is inefficient and we dont exit early.

A sample function in the workflow is as follows:

let StepB stepAResult someParameters =
    match stepAResult with
    | Good(validResourceData) ->
        // Do current step processing
        // Return current step result
    | Error(error) -> error |> Result.Error

The workflow itself is like the following:

let Workflow someParameters =
    let stepAResult = StepA someParameters
    let stepBResult = StepB stepAResult someParameters
    let stepCResult = StepC stepBResult someParameters
    let stepDResult = StepD stepCResult someParameters
    stepDResult

So each sample function would take in the result of the previous function and only execute the current step if there was no Error!

The problem I have with this is that if StepA fails with an Error, every other step is still called.

Is there a "functional" way of "returning early" instead of calling every function in the workflow, where we must check each time for an Error?

like image 972
bstack Avatar asked Apr 24 '15 14:04

bstack


Video Answer


1 Answers

You write your functions under the assumption, that all went well as you have done. Then you unwrap the happy case and continue with the happy case.

And in the end, you can use the builder to make the syntax pretty.

type Result<'TSuccess, 'TError> = 
    | Success of 'TSuccess
    | Error of 'TError

type ResultBuilder() =
    member this.Bind(v, f) =
        match v with
        | Success v -> f v
        | Error e -> Error e

    member this.Return value = Success value

let result = ResultBuilder()

let bla<'a> = result {
    let! successOne = Success 1
    let! successTwo = Success 2
    let! failure = Error "after this, the computation exited"
    failwith "Boom, won't occurr"
    return successOne + successTwo }
like image 119
Daniel Fabian Avatar answered Sep 18 '22 17:09

Daniel Fabian