[Ur] Poor inference of monads over "non-canonical" types
Evan Danaher
ur at edanaher.net
Sat Feb 22 01:34:42 EST 2014
Thanks for the quick reply!
As usual, the answer is obvious in hindsight: the issue is with
"non-canonical" types, so make in canonical by wrapping it in a
constructor. There can be ambiguity if there are multiple matches;
avoid that by wrapping it in a (unique) constructor.
On the upside, in fighting this, I'm getting much more comfortable with
the type system on an intuitive level, which is definitely valuable.
On Sat, Feb 22, 2014 at 12:12:16AM -0500, Patrick Hurst wrote:
> Your code is equivalent to this in Haskell:
>
> type Pair a = (a, a)
>
> instance Monad Pair where
> return = undefined
> (>>=) = undefined
>
> which is illegal. The Haskell way to do it would be:
>
> data Pair' a = MkPair (a, a)
>
> instance Monad Pair' where
> return = undefined
> (>>=) = undefined
>
> The difference is that [(2, 3) :: Pair Int] is valid, but [(2, 3) ::
> Pair' Int] isn't; you need to apply [MkPair :: (a, a) -> Pair' a] to get
> [MkPair (2, 3) :: Pair' Int].
>
> The Ur/Web equivalent of this would be
>
> datatype pair a = Pair of a * a
> val pairMonad : monad pair = mkMonad {
> Return = fn [t ::: Type] (a : t) => Pair (a, a),
> Bind = fn [t1 ::: Type] [t2 ::: Type] ((Pair (a, a')) : pair t1) (b : t1 -> pair t2) => b a
> }
>
> val fail : pair int =
> return 4
>
> which does work.
>
>
> Evan Danaher <ur at edanaher.net> writes:
>
> > I'm writing a simple parser, and decided to try my hand at a
> > Parsec-like monadic combinator approach. Unfortunately, it seems that
> > monad inference is fairly weak; consider the following:
> >
> > con pair t = t * t
> > val pairMonad : monad pair = mkMonad {
> > Return = fn [t ::: Type] (a : t) => (a, a),
> > Bind = fn [t1 ::: Type] [t2 ::: Type] ((a, a') : pair t1) (b : t1 -> pair t2) => b a
> > }
> >
> > val fail : pair int =
> > return 4
> >
> > (Yes, that's not actually a monad, but the types work.) This fails to compile:
> >
> > Expression: return [<UNIF:U338::Type -> Type>] [int] _ 4
> > Have con: <UNIF:U338::Type -> Type> int
> > Need con: int * int
> > Incompatible constructors
> > Have: <UNIF:U338::Type -> Type> int
> > Need: int * int
> >
> > It looks like the compiler is simplifying (pair int) to (int * int), then
> > failing to unify it with the (M t) pattern to pull out the monad. Sure enough:
> >
> > val fail : pair int =
> > @return pairMonad 4
> >
> > works just fine, since pairMonad provides the monad, and then unifying (t * t)
> > with (int * int) doesn't cause any trouble.
> >
> > I can see why this could be tricky, and in general possibly ambiguous. (E.g.,
> > if there's a second monad (con withInt t = t * int), int * int could be either
> > of them.) However, I'd expect it to be reasonable to take the given type (pair
> > int) and use that one. (How does Haskell handle this?)
> >
> > Moreover, this (AFAICT) completely breaks the syntactic sugar for monads; I'd
> > like to be able to write something like
> >
> > command <- Parse.word;
> > args <- Parse.arguments;
> > return {Command=command, Args=args}
> >
> > but the suger doesn't seem to provide any way to annotate the monad, rendering
> > it uncompilable.
> >
> > Hopefully the problem is clear; am I missing an obvious solution? I can't find
> > anything in the bug tracker about this; I can't imagine I'm the first to run
> > into it.
> >
> > _______________________________________________
> > Ur mailing list
> > Ur at impredicative.com
> > http://www.impredicative.com/cgi-bin/mailman/listinfo/ur
>
More information about the Ur
mailing list