[Ur] Poor inference of monads over "non-canonical" types
Patrick Hurst
phurst at mit.edu
Sat Feb 22 00:12:16 EST 2014
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