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 }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With