fsprojects / fsprojects/FSharpPlus
Consider adding a phantom type to Kleisli
Nobody has claimed this yet.
- Dominant language
- F#
- Stars
- 941
- Forks
- 106
- PR merge metrics
- No merged PRs in 30d
Description
We could get better types, but we risk more value restrictions.
For instance, defining it like this:
/// Kleisli arrows of a monad. Represents a function 'T -> 'Monad<'U>
[<Struct; NoEquality; NoComparison>]
type Kleisli<'t, '``monad<'u>``,'u> = Kleisli of ('t -> '``monad<'u>``) with
// Profunctor
static member inline Dimap (Kleisli bmc: Kleisli<'B,'``Monad<'C>``,'C>, ab: 'A->'B, cd: 'C->'D) = let cmd = map cd in Kleisli (ab >> bmc >> cmd) : Kleisli<'A,'``Monad<'D>``,'D>
static member Contramap (Kleisli f : Kleisli<'B,'``Monad<'C>``,'C>, k: 'A->'B) = Kleisli (k >> f) : Kleisli<'A,'``Monad<'C>``,'C>
static member inline Map (Kleisli f : Kleisli<'B,'``Monad<'C>``,'C>, cd: 'C->'D ) = Kleisli (map cd << f) : Kleisli<'B,'``Monad<'D>``,'D>
// Category
static member inline get_Id () = Kleisli result : Kleisli<'a,'b,'a>
static member inline (<<<) (Kleisli (f: 'U->'``Monad<'V>``): Kleisli<'U,'``Monad<'V>``,'V>, Kleisli (g: 'T->'``Monad<'U>``): Kleisli<'T,'``Monad<'U>``,'U>) =
Kleisli ( (g >=> f) : 'T->'``Monad<'V>``) : Kleisli<'T, '``Monad<'V>``, 'V>
Allows us to run:
let r5: List<_> = (runKleisli (getCatId ())) 5
let k = Kleisli (fun y -> [y; y * 2 ; y * 3]) <<< Kleisli (fun x -> [x + 3; x * 2])
let r8n16n24n10n20n30 = runKleisli k 5
But we get a value restriction
error FS0030: Value restriction. The value 'k' has been inferred to have generic type
[<Struct>]
val k : Kleisli<int,int list,'_a>
Either define 'k' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
that we can avoid, by not let-binding k
let r5: List<_> = (runKleisli (getCatId ())) 5
let r8n16n24n10n20n30 = runKleisli (Kleisli (fun y -> [y; y * 2 ; y * 3]) <<< Kleisli (fun x -> [x + 3; x * 2])) 5
or by adding another constraint:
static member inline (<<<) (Kleisli (f: 'U->'``Monad<'V>``): Kleisli<'U,'``Monad<'V>``,'V>, Kleisli (g: 'T->'``Monad<'U>``): Kleisli<'T,'``Monad<'U>``,'U>) =
let _ = if true then Unchecked.defaultof<'``Monad<'V>``> else result (Unchecked.defaultof<'V>)
Kleisli ( (g >=> f) : 'T->'``Monad<'V>``) : Kleisli<'T, '``Monad<'V>``, 'V>
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No file or test is named. Start by locating the Kleisli definition and its category-composition operator, then reproduce the shown value-restriction example. Done requires a decision on the phantom-type approach and, if accepted, verification that let-bound composition works without introducing the stated value restrictions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- fsharp
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100