Reputation: 1526
struct Z;
struct S<N>(N);
struct MinHelper<N1, N2>(N1, N2);
trait Min {
type Val;
}
impl<N1> Min for MinHelper<N1, Z> {
type Val = Z;
}
impl<N2> Min for MinHelper<Z, S<N2>> {
type Val = Z;
}
impl<N1, N2> Min for MinHelper<S<N1>, S<N2>>
where
MinHelper<N1, N2>: Min,
{
type Val = S<<MinHelper<N1, N2> as Min>::Val>;
}
fn min<N1, N2>(_1: N1, _2: N2) -> <MinHelper<N1, N2> as Min>::Val {
unimplemented!()
}
It seems that the problem is in the type checking of functions. If I use Min
like this, it behaves well:
let x: <MinHelper<S<Z>, S<S<Z>>> as Min>::Val = S(Z);
What I want to implement is type families in Haskell:
{-# LANGUAGE TypeFamilies #-}
data Z;
data S n;
type family Min (a :: *) (b :: *) :: *;
type instance Min a Z = Z
type instance Min Z b = Z
type instance Min (S a) (S b) = S (Min a b)
min :: a -> b -> Min a b
min = undefined
Upvotes: 3
Views: 204
Reputation: 1526
I found a solution for this:
struct Z;
struct S<N>(N);
struct Helper;
trait Min<N1, N2> {
type Val;
}
impl<N1> Min<N1, Z> for Helper {
type Val = Z;
}
impl<N2> Min<Z, S<N2>> for Helper {
type Val = Z;
}
impl<N1, N2> Min<S<N1>, S<N2>> for Helper
where
Helper: Min<N1, N2>,
{
type Val = S<<Helper as Min<N1, N2>>::Val>;
}
fn min<N1, N2>(_a: N1, _b: N2) -> <Helper as Min<N1, N2>>::Val
where
Helper: Min<N1, N2>,
{
unimplemented!()
}
fn main() {
min(S(Z), S(S(Z)));
}
I still haven't found a detailed explanation. But @LambdaFairy 's comment sounds reasonable.
Upvotes: 1