Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does F# Guideline recommend to declare module & type having the same name?

After reading F# Component Design Guidelines, I don't see any comment whether I should declare module & its type to have the same name.

Usually my projects don't have any cyclic dependency, so I don't need to make a new module (e.g. InfrastructureTypes or DomainTypes) to put every types in one place.

For example, if I have a record type System and a bunch of its functions, should I put everything inside one module file? This is my attempt:

// System.fs
module System

type rec System =
    { name : string
      children : System list }

let init () = { name = ""; children = [] }

let addChild system child =
    { system with system.children = child :: system.children }

let removeChild system child =
    let rec removeChild children acc child =
        match children with
        | c :: children ->
            if c <> child then removeChild children (c :: acc) child
            else removeChild children acc child
        | [] -> List.rev acc

    let children = removeChild system.Children [] child
    { system with system.children = children }
like image 333
MiP Avatar asked Jun 12 '17 03:06

MiP


1 Answers

It is a common approach in the F# core library itself to have a module and type with the same name at the same level (as opposed to having the type inside the module like in your example). For example, there is a List<'a> type and a List module that contains the function that contains functions for working with it. Similarly with Option, Set, Result etc.

If you already had a type with a given name, there is an attribute you can add to to allow creating a module with the same name without a compiler error: [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]

However, since F# 4.1, this is implicit. So defining a module with the same name as the type just works, and the word Module will be at the end of the module name when the code is compiled.

type System =
    { name : string
      children : System list }

module System =
    let init () = { name = ""; children = [] }

I think all this implies that this can be a valid pattern to use in F#. Particularly when you have a good abstraction. You might want to look up "abstract data types" as I think they apply here.

Looking at the examples I've given above, this is normally more of a library-level pattern, but I've heard the argument that it can be applied to good effect in application code too. I can imagine that it could help you to think about and enforce abstraction boundaries and keep code organised.

like image 127
TheQuickBrownFox Avatar answered Oct 28 '22 23:10

TheQuickBrownFox