amuletml / amulet

An ML-like functional programming language
https://amulet.works/
BSD 3-Clause "New" or "Revised" License
328 stars 16 forks source link

Order of type parameters is important? #250

Closed Lupus closed 4 years ago

Lupus commented 4 years ago

I'm trying to create Result type, but I can't make it instance of functor. Here's my code:

module Result =
  type t 'a 'b =
  | Ok of 'a
  | Error of 'b

  instance functor (t 'a) begin
    let f <$> x =
      match x with
      | Ok b -> Ok (f b)
      | Error a -> Error a
  end

Type checker is not happy about that unless I swap type parameters (i.e. write t 'b 'a):

lib.aml[63:17 ..63:24]: error (E2009)
  Could not match the rigid type variable 'b with the type 'a

  • Arising in this expression
   │ 
63 │       | Ok b -> Ok (f b)
   │                 ^^^^^^^^

  • When checking that this expression
   │ 
61 │     let f <$> x =
   │         ^^^^^^^^^
  has type forall 'a 'b. ('a -> 'b) -> t 'a 'a -> t 'a 'b
lib.aml[63:23 ..63:23]: error (E2009)
  Could not match the rigid type variable 'a with the type 'a

  Where the type variable functor (t 'a) is bound by the instance being defined
   │ 
60 │   instance functor (t 'a) begin
   │   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  • Arising in the this expression
   │ 
63 │       | Ok b -> Ok (f b)
   │                       ^
lib.aml[63:17 ..63:24]: error (E2009)
  Could not match the rigid type variable 'b with the type 'a

  • Arising in this expression
   │ 
63 │       | Ok b -> Ok (f b)
   │                 ^^^^^^^^

  • When checking that this expression
   │ 
61 │     let f <$> x =
   │         ^^^^^^^^^
  has type forall 'a 'b. ('a -> 'b) -> t 'a 'a -> t 'a 'b
lib.aml[64:26 ..64:26]: error (E2009)
  Could not match the rigid type variable 'a with the type 'b

  • Arising in this expression
   │ 
64 │       | Error a -> Error a
   │                          ^

  • When checking that this expression
   │ 
61 │     let f <$> x =
   │         ^^^^^^^^^
  has type forall 'a 'b. ('a -> 'b) -> t 'a 'a -> t 'a 'b

The following message has a detailed explanation: 2009.
Try 'amc explain 2009' to see it.

I really want to have type for Ok to be the first one, it makes more sense this way.

I'm using 0.7.0.0 (bbe61c6680).

SquidDev commented 4 years ago

Types, type classes and type functions are just like normal functions, in that the order does matter. Thus we sadly do end up with annoying cases where type classes mandate that parameters appear in a specific order.

I'm afraid there's not really an optimal solution here, aside from "just swap them" (which is what we do for the either type). If we had type lambdas, you could have some type-level equivalent of "flip", but that would add a lot of complexity to the type system, and I'm not sure that's a route we want to go down yet.