Closed gcanti closed 7 years ago
@gcanti Would that be a start (I'm hesitating between 'promap' or 'dimap')?
export interface StaticProfunctor<F extends HKT2S> {
lmap<A, B, C>(fa: (a: A) => B, m: HKT2<B, C>[F]): HKT2<A, C>[F]
rmap<B, C, D>(fb: (c: C) => D, m: HKT2<B, C>[F]): HKT2<B, D>[F]
promap<A, B, C, D>(fa: (a: A) => B, fb: (c: C) => D, m: HKT2<B, C>[F]): HKT2<A, D>[F]
}
export interface FantasyProfunctor<F extends HKT2S, B, C> {
lmap<A, B, C>(fa: (a: A) => B): HKT2<A, C>[F]
rmap<B, C, D>(fb: (c: C) => D): HKT2<B, D>[F]
promap<A, D>(fa: (a: A) => B, fb: (c: C) => D): HKT2<A, D>[F]
}
insight on how you would encode partial type application in order to follow the spec?
Module must match the Profunctor signature for some type T, support Functor algebra for all types U created by setting the first parameter of T to an arbitrary concrete type (for example type U = T<number, a>)
I have this but it enforces nothing (besides 'D'):
export function toFunctor<F extends HKT2S, B, C, D>(m: FantasyProfunctor<F, B, C>): FantasyFunctor<F, C> {
return ({
map(f: (a: C) => D): HKT<D>[F] {
return m.rmap(f);
}
});
}
Another approach:
export interface FantasyProfunctor<F extends HKT2S, B, C> {
lmap<A, B, C>(fa: (a: A) => B): HKT2<A, C>[F]
rmap<B, C, D>(fb: (c: C) => D): HKT2<B, D>[F]
promap<A, D>(fa: (a: A) => B, fb: (c: C) => D): HKT2<A, D>[F]
toFunctor<D>(): FantasyFunctor<F, C>; // this could be the solution but we can only fix 'D' parameter in the implemented instance
}
So this generates an error because 'D' is a phantom and not bound to anything.. I can't see how to enforce something properly here..
Or we can simply do something like that for FantasyLand:
export interface FantasyProfunctor<F extends HKT2S, B, C> extends FantasyFunctor<F, C> {
lmap<A, B, C>(fa: (a: A) => B): HKT2<A, C>[F]
rmap<B, C, D>(fb: (c: C) => D): HKT2<B, D>[F]
promap<A, D>(fa: (a: A) => B, fb: (c: C) => D): HKT2<A, D>[F]
map<D>(f: (a: C) => D): HKT<D>[F] // no escape from the Functor
map<D>(f: (a: C) => D): HKT<D>[F] & HKT2<B, D>[F] // would that be acceptable?
}
When thinking about StaticLand, it's the same story as Either, the first type param would become any.
Waiting for your feedback..
Also, not sure what interesting instances should be implemented.. (Arrows ?)
I'm hesitating between 'promap' or 'dimap'
Yeah, purescript uses dimap
https://github.com/purescript/purescript-profunctor/blob/master/src/Data/Profunctor.purs#L23, I would stick with static-land though (as done so far), so promap
import { HKT2, HKT2S } from './HKT'
import { StaticFunctor, FantasyFunctor } from './Functor'
import { identity } from './function'
export interface StaticProfunctor<F extends HKT2S> extends StaticFunctor<F> {
promap<A, B, C, D>(ab: (a: A) => B, cd: (c: C) => D, fbc: HKT2<B, C>[F]): HKT2<A, D>[F]
}
export interface FantasyProfunctor<F extends HKT2S, B, C> extends FantasyFunctor<F, C> {
promap<A, D>(ab: (a: A) => B, cd: (c: C) => D): HKT2<A, D>[F]
}
lmap
and rmap
can be derived (like lift
in Functor
)
export function lmap<F extends HKT2S, A, B, C>(profunctor: StaticProfunctor<F>, f: (a: A) => B, fbc: HKT2<B, C>[F]): HKT2<A, C>[F] {
return profunctor.promap<A, B, C, C>(f, identity, fbc)
}
// this is just the functor map
export function rmap<F extends HKT2S, A, B, C>(profunctor: StaticProfunctor<F>, f: (a: B) => C, fab: HKT2<A, B>[F]): HKT2<A, C>[F] {
return profunctor.map(f, fab)
}
insight on how you would encode partial type application in order to follow the spec?
extends StaticFunctor<F>
and extends FantasyFunctor<F, C>
should be enough I guess
Also, not sure what interesting instances should be implemented
Theoretically functions ->
(though we need a wrapper in TypeScript, see below), profunctor optics, other examples here https://github.com/purescript/purescript-profunctor/tree/master/src/Data/Profunctor and here https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/profunctors
Functions as profunctors
declare module './HKT' {
interface HKT<A> {
'->': Fun<any, A>
}
interface HKT2<A, B> {
'->': Fun<A, B>
}
}
export const URI = '->'
export type URI = typeof URI
export class Fun<B, A> implements FantasyProfunctor<URI, B, A> {
readonly _B: B
readonly _A: A
readonly _URI: URI
constructor(public readonly value: (b: B) => A) {}
run(b: B): A {
return this.value(b)
}
map<C>(f: (a: A) => C): Fun<B, C> {
return this.promap<B, C>(identity, f)
}
promap<C, D>(cb: (c: C) => B, ad: (a: A) => D): Fun<C, D> {
return new Fun<C, D>(c => ad(this.run(cb(c))))
}
}
https://github.com/rpominov/static-land/blob/master/docs/spec.md#profunctor