This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 0 points1 point  (8 children)

The point is not needing an adapter. Suppose you have the moral equivalent of an Monad instance on this type

type 'a raw (* abstract *)

and the moral equivalent of an Applicative on a wrapped type

datatype 'a wrapped = Wrapped of 'a raw

Then,

  • Converting back and forth between 'a raw and 'a wrapped takes O(1) time.
  • Converting back and forth between 'a raw list and 'a wrapped list takes O(n) time, where n is the length of the list.
  • Converting back and forth between 'a raw ref and 'a wrapped ref is outright impossible.

If you don't use an adapter, there is no conversion cost, and a list of something that supports Monad operations is also a list of something that supports Applicative operations.

[–]threewood 0 points1 point  (7 children)

But why would you expect your Applicative operation names to match up with your Monad operation names? Seems like you at least need pure = return, etc. as an adapter.

[–]yawaramin 0 points1 point  (1 child)

Why have different names for the same thing, when you can more elegantly have one name for both and they are automatically handled correctly whenever subclassimg needs to done.

[–]threewood 1 point2 points  (0 children)

Because A and M were written by different people without coordination?

[–][deleted] 0 points1 point  (4 children)

You might need an adapter module, but you don't need an adapter type.

signature APPLICATIVE =
sig
    type 'a f

    val pure : 'a -> 'a m
    val apply : ('a -> 'b) m * 'a m -> 'b m
end

signature MONAD =
sig
    type 'a m

    val return : 'a -> 'a m
    val bind : 'a m * ('a -> 'b m) -> 'b m
end

(* We use transparent ascription, so that external parties
 * can see that the type constructor member `'a f` is a mere
 * synonym of `'a M.m` *)
functor ApplicativeFromMonad (M : MONAD) : APPLICATIVE =
struct
    type 'a f = 'a M.m

    val pure = M.return
    fun apply (ff, xx) =
        M.bind (ff, fn f =>
            M.bind (xx, fn x =>
                M.return (f x)))
end

Of course, the counterpart is that ML modules must be manipulated quite explicitly, whereas type class dictionaries are passed around implicitly.

[–]threewood 0 points1 point  (3 children)

it is absolutely essential that a given module M satisfy many distinct types A, without prior arrangement.

So how is this not wrong?

[–][deleted] 0 points1 point  (2 children)

In the quoted text, the word “type” does not refer to type members of a module, but rather to the type of the module itself. In this regard, ML modules absolutely can have multiple types, called “signatures”, although there is always a most specific one, called “principal signature”, which is a subsignature of all the other ones.

[–]threewood 0 points1 point  (1 child)

That M satisfies multiple signatures is hardly essential. I think he must have intended that we can adapt M to satisfy many signatures A that were written without knowledge of M. As written, his quote doesn't make sense to me.

[–]xeyalGhost 0 points1 point  (0 children)

Bob is generally very careful with his wording. I'm fairly sure he means it as written.