From Haskell to F#

We start from an image of the Haskell code from  Comonadic builders by Dmitrii Kovanikov .


First we need to focus on one of the most important “take-aways“:

The key observation here: our initial buildProject function mappends all passed settings first and only then creates Project. So we can build the Project first and later perform post-analysis to decide how to set the flag.

For the Settings, We find the Semigroup implementation of Any in FSharpPlus

type Settings =  
        settingsHasLibrary: Any; 
        settingsGitHub: Any;
        settingsTravis: Any
    static member get_Zero () = {
            settingsHasLibrary =  getZero(); 
            settingsGitHub = getZero(); 
            settingsTravis = getZero()
    static member (+) ((x:Settings), (y:Settings)) = {
        settingsHasLibrary = x.settingsHasLibrary + y.settingsHasLibrary;
        settingsGitHub = x.settingsGitHub + y.settingsGitHub;
        settingsTravis = x.settingsTravis + y.settingsTravis

Now we want to apply the associative binary operation of the Semigroup. And this is awesome, we can find getAny in the F# porting of the Haskell Prelude!

let getAny (Any x) = x

let inline buildProject name  (settings:^Settings) = 
        projectName = name; 
        projectHasLibrary = getAny settings.settingsHasLibrary;
        projectGitHub = getAny settings.settingsGitHub;
        projectTravis = getAny settings.settingsTravis
So we can finally write our builders as follows!
let inline append (b:(^Settings -> ^Project)) (f: (^Settings -> ^Project) -> Project) : (^Settings -> ^Project)  =
     extend f b 

let inline  (>>=) b f = append b f

let inline hasLibraryB (builder:(^Settings -> ^Project)) = 
        builder { 
        with settingsHasLibrary = Any true;} 

let inline gitHubB (builder:(^Settings -> ^Project)) = 
        builder { 
        with settingsGitHub = Any true;} 

let inline travisB (builder:(^Settings -> ^Project)) =
    let project = extract builder
    let x = project.projectGitHub
    { project with projectTravis = x }

let main argv = 
    extract <| 
    buildProject "minimal-project" 
    |> printfn "%A"

    extract <| 
    (append (buildProject "sd") hasLibraryB ) 
    |> printfn "%A"
    extract <| 
    ((buildProject "library github") >>= hasLibraryB >>= gitHubB) 
    |> printfn "%A"
    extract <| 
    (append (buildProject "travis") travisB ) 
    |> printfn "%A"
    extract <| 
    ((buildProject "travis github") >>= travisB >>= gitHubB) 
    |> printfn "%A"

    extract <| 
    ((buildProject "github travis") >>= gitHubB >>= travisB)
    |> printfn "%A" 

2 thoughts on “From Haskell to F#

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s