How do I condense this repetitive F# code?

why f#
fsharp for profit
f# forfunandprofit
f# helper function
f# chaining
f# application
thinking functionally f#
f# callback

EDIT: possible solutions at bottom

I'm doing some data work where I need to be very careful about string lengths that will eventually be sent in fixed width text output, stored in limited size nvarchar fields, etc. I want to have good strict typing for these rather than naked System.String types.

Suppose I've got some code like this to represent these, with a few useful module functions that play nicely with Result.map, Option.map, etc.

module String40 =
    let private MaxLength = 40
    type T = private T of string
    let create (s:string) = checkStringLength MaxLength s |> Result.map T
    let trustCreate (s:string) = checkStringLength MaxLength s  |> Result.okVal |> T
    let truncateCreate (s:string) = truncateStringToLength MaxLength s |> T
    let toString (T s) = s

    type T with
        member this.AsString = this |> toString


module String100 =
    let private MaxLength = 100
    type T = private T of string
    let create (s:string) = checkStringLength MaxLength s |> Result.map T
    let trustCreate (s:string) = checkStringLength MaxLength s  |> Result.okVal |> T
    let truncateCreate (s:string) = truncateStringToLength MaxLength s |> T
    let toString (T s) = s

    type T with
        member this.AsString = this |> toString

Obviously these are almost entirely repetitive with only the module name and max length different in each block.

What options are available to try and cut down on the repetitiveness here? I would love to have something like this:

type String40 = LengthLimitedString<40>
type String100 = LengthLimitedString<100>

tryToRetrieveString ()   // returns Result<string, ERRType>
|> Result.bind String40.create
  • T4 code generation doesn't seem to be an option for F# projects
  • Type providers seem like overkill for this kind of simple templating, and as best as I can tell they can only produce classes, not modules.
  • I'm aware of Scott Wlaschin's constrained strings page, but I end up with roughly the same level of repetitive code in the 'Create a type', 'Implement IWrappedString', 'create a public constructor' steps he lists.

These code blocks are fairly short and it wouldn't be the end of the world to just copy/paste a dozen times for the different field lengths. But I feel like I'm missing a simpler way to do this.

UPDATE:

One other note is that it's important that records using these types give information about what type they're carrying:

type MyRecord = 
  {
    FirstName: String40;
    LastName: String100;
  }

and not be something like

type MyRecord = 
  {
    FirstName: LimitedString;
    LastName: LimitedString;
  }


Tomas' answer, using the Depended Type Provider nuget library is a pretty good one, and would be a good solution for a lot of people who are fine with its behavior as-is. I felt like it would be a little tricky to extend and customize unless I wanted to maintain my own copy of a type provider which I was hoping to avoid.

Marcelo's suggestion of static parameter constraints was a fairly productive path of research. They give me basically what I was looking for -- a generic argument that is basically an 'interface' for a static methods. However the kicker is that they require inline functions to operate and I don't have the time to evaluate how much that would or would not matter in my code base.

But I took that and altered it to use regular generic constraints. It's a bit goofy to have to instantiate an object to get a max-length value, and fsharp type/generic code is just gross to look at, but from the module users's perspective it's clean, and I can easily extend this however I want.

    type IMaxLengthProvider = abstract member GetMaxLength: unit -> int

    type MaxLength3 () = interface IMaxLengthProvider with member this.GetMaxLength () = 3
    type MaxLength4 () = interface IMaxLengthProvider with member this.GetMaxLength () = 4


    module LimitedString =

        type T< 'a when 'a :> IMaxLengthProvider> = private T of string

        let create< 't when 't :> IMaxLengthProvider and 't : (new:unit -> 't)> (s:string) =
            let len = (new 't()).GetMaxLength()
            match checkStringLength len s with
            | Ok s ->
                let x : T< 't> = s |> T
                x |> Ok
            | Error e -> Error e
        let trustCreate< 't when 't :> IMaxLengthProvider and 't : (new:unit -> 't)> (s:string) =
            let len = (new 't()).GetMaxLength()
            match checkStringLength len s with
            | Ok s ->
                let x : T< 't> = s |> T
                x
            | Error e -> 
                let msg = e |> formErrorMessage
                failwith msg

        let truncateCreate< 't when 't :> IMaxLengthProvider and 't : (new:unit -> 't)> (s:string) =
            let len = (new 't()).GetMaxLength()
            let s = truncateStringToLength len s
            let x : T< 't> = s |> T
            x

        let toString (T s) = s
        type T< 'a when 'a :> IMaxLengthProvider> with
            member this.AsString = this |> toString


    module test =
        let dotest () =

            let getString () = "asd" |> Ok

            let mystr = 
                getString ()
                |> Result.bind LimitedString.create<MaxLength3>
                |> Result.okVal
                |> LimitedString.toString

            sprintf "it is %s" mystr

Can't you use Static Parameters, as shown on the F#.Data package's HtmlProvider example?

f# - FP - Condense and 'nice' code, Writing code in F# in most cases results in very condense an intuitive work. This piece of code looks somehow imperative and inconvenient to me. times is an array How do I condense this repetitive F# code? 1 · How to write  Pieces of identical code should be replaced with a single method. So the fix would be to extract the method and delegate to common behaviour. in the same method, perform Extract Local Variable and reuse it. in the same class perform the Extract Method refactoring.


I think the BoundedString type provider from the Dependent type provider project lets you do exactly what you need. Using the example from the project documentation, you can do e.g.:

type ProductDescription = BoundedString<10, 2000>
type ProductName = BoundedString<5, 50>

type Product = { Name : ProductName; Description : ProductDescription }

let newProduct (name : string) (description : string) : Product option =
  match ProductName.TryCreate(name), ProductDescription.TryCreate(description) with
  | Some n, Some d -> { Name = n; Description = d }
  | _ -> None

I don't know how many people use this project in practice, but it seems quite simple and it does exactly what you were asking for, so it might be worth a try.

Conciseness, In F# it is extremely easy to extract repetitive code into common utility of basic operations and then combine these building blocks in various  Start studying Chapter 10-2: Chromosome Organization and Molecular Structure. Learn vocabulary, terms, and more with flashcards, games, and other study tools.


Using a touch of careful reflection magic, we can achieve a lot and get some really nice types. How about something like this?

module Strings =
    type [<AbstractClass>] Length(value: int) =
        member this.Value = value

    let getLengthInst<'L when 'L :> Length> : 'L =
        downcast typeof<'L>.GetConstructor([||]).Invoke([||])

    type LimitedString<'Length when 'Length :> Length> =
        private | LimitedString of maxLength: 'Length * value: string

        member this.Value =
            let (LimitedString(_, value)) = this in value
        member this.MaxLength =
            let (LimitedString(maxLength, _)) = this in maxLength.Value

    module LimitedString =
        let checkStringLength<'L when 'L :> Length> (str: string) =
            let maxLength = getLengthInst<'L>.Value
            if str.Length <= maxLength then Ok str
            else Error (sprintf "String of length %d exceeded max length of %d" str.Length maxLength)

        let create<'L when 'L :> Length> (str: string) =
            checkStringLength<'L> str
            |> Result.map (fun str -> LimitedString (getLengthInst<'L>, str))

open Strings

// === Usage ===

type Len5() = inherit Length(5)
type Len1() = inherit Length(1)

// Ok
LimitedString.create<Len5> "Hello"
// Error
LimitedString.create<Len1> "world"

Using functions to extract boilerplate code, Is there a way to strip the duplicate code and focus on the just the the code is more condensed than the C# version (4-5 lines of F# code vs. at  That “[#100 EQ 0]” is a conditional expression that checks whether the value of #100 is zero. If it is, the G-Code will perform a GOTO taking it to N110. If its value isn’t zero, the G-Code falls through to the next line, which we see is an alternate GOTO that takes us to N200. That’s how conditional branching with IF and GOTO work together.


One option might be to use a single module for limited-length strings that uses curried parameters for the length-limit and the string itself, then just partially apply the limit parameter. An implementation might look like this:

module LimitedString =
    type T = private T of string
    let create length (s:string) = checkStringLength length s |> Result.map T
    let trustCreate length (s:string) = checkStringLength length s  |> Result.okVal |> T
    let truncateCreate length (s:string) = truncateStringToLength length s |> T
    let toString (T s) = s

    type T with
        member this.AsString = this |> toString

Then, your modules for each length would still be required, but wouldn't have all the boilerplate:

module String100 =
    let create = LimitedString.create 100
    let trustCreate = LimitedString.trustCreate 100
    let truncateCreate = LimitedString.truncateCreate 100

EDIT

After reading the comment and the update to the original post, I would change my suggestion a bit. Instead of defining the T type inside each module, I would have a specific struct-type single-case union for each string length at the top level. Then, I would move to toString to the individual string modules. Finally, I would add one more parameter to the LimitedString module to allow us to partially apply both the length and the specific single-case union type:

[<Struct>] type String40 = private String40 of string
[<Struct>] type String100 = private String100 of string

module LimitedString =
    let create length ctor (s:string) = checkStringLength length s |> Result.map ctor
    let trustCreate length ctor (s:string) = checkStringLength length s  |> Result.okVal |> ctor
    let truncateCreate length ctor (s:string) = truncateStringToLength length s |> ctor

module String40 =
    let create = LimitedString.create 40 String40
    let trustCreate = LimitedString.trustCreate 40 String40
    let truncateCreate = LimitedString.truncateCreate 40 String40
    let toString (String40 s) = s

module String100 =
    let create = LimitedString.create 100 String100
    let trustCreate = LimitedString.trustCreate 100 String100
    let truncateCreate = LimitedString.truncateCreate 100 String100
    let toString (String100 s) = s

type MyRecord =
    {
        FirstName: String40
        LastName: String100
    }

There's still a fair amount of boilerplate here, but I think this is in the ballpark for a solution using single-case unions and modules. A Type Provider might be possible, but you would have to consider whether the added complexity outweighs the boilerplate.

An Introduction To F# Type Providers - F# tutorial, One pain point that developers frequently experience in any language is the need to write repetitive boilerplate code. For example, when  want to remove repetitive info from a column When I import CSV data into excel I want to be able to remvoe the repetitive information in a certain column. Eg if I had sheet that was sorted by state I only want the state to show up the first time.


F# code formatting guidelines, This article offers guidelines for how to format your code so that your F# code is: More legible; In accordance with conventions applied by  Repetitive strain injury (RSI) is a general term used to describe the pain felt in muscles, nerves and tendons caused by repetitive movement and overuse. It's also known as work-related upper limb disorder, or non-specific upper limb pain. The condition mostly affects parts of the upper body, such as the: forearms and elbows ; wrists and hands


[PDF] The F# 4.1 Language Specification, The use of lightweight syntax is the default for all F# code in files with the indicates repetition of the preceding non-terminal construct and the separator token. After a function or member definition is generalized, its type is condensed by  Looking for a better way use multiple pure functions to condense repetitive code. Ask Question Now I do a single computation that computes the first and last


F# Math (IV.) - Writing generic numeric code, Generic numeric code differs from ordinary generic F# code such as the 'a list type To call the method inside the body of the function, we need to repeat the However, it is possible to combine the approach based on static  Authoring an F#/C# VSIX project template is an easy way to encourage reuse and reduce time wasted on repetitive project setup tasks. With these skills now in your possession, you’ll be able to increase productivity by creating project templates that contain as little or as much complexity as your scenario requires.