3 ms·
I was wondering about that. "Monad" is a mildly obfuscatory term for "function that takes one argument and returns one value of the same type", and a List is no
by pjc50 10mo ago
I was wondering about that. "Monad" is a mildly obfuscatory term for "function that takes one argument and returns one value of the same type", and a List is not a function.
- mrkeen 10mo agoWhere did you get that definition? "function that takes one argument and returns one value of the same type" is the identity function.
- epolanski 10mo agoIdentity function returns the same _value_. If it's only the same _type_, but the value is not the same, then it's an endomorphism. The function definitions look the same `a -> a`. string reversal, integer negation or toUpperCase are classical examples of endomorphisms. Identity is a specific case of endomorphism.
- mrkeen 10mo agostring reversal, integer negation or toUpperCase are classical examples of functions which will not compile as `a -> a` The function which will compile as `a -> a` is the identity function.
- epolanski 10mo agoThat's correct, but I'm not sure how it relates to my comment as I said that `a -> a` is just an endomorphism. identity, uppercase or negate are all endomorphisms, with identity being the only generic one.
- louthy 10mo agoI think you're describing part of the bind function, which is part of the definition of the monad interface: a -> m b But the full definition is: bind :: (a -> m b) -> m a -> m b In C#, it would look like this: M<B> Bind(Func<A, M<B>> f, M<A> ma) Assuming a future version of C# that supports higher-kinds that is. In my language-ext library, I achieve a higher-kinded monad trait [1], like so: public interface Monad<M> : Applicative<M>, where M : Monad<M> { static abstract K<M, B> Bind<A, B>(K<M, A> ma, Func<A, K<M, B>> f); } Which is what the original comment is about. Most people in C# are not creating monads when they implement Bind or SelectMany for their type. They are simply making 'do-notation' work (LINQ). The monad abstraction isn't there until you define the Monad trait that allows the writing of any function constrained to said trait. For example, a `When` function that runs the `then` monad when the `predicate` monad returns `true` for its bound value: public static K<M, Unit> When<M>(K<M, bool> predicate, K<M, Unit> then) where M : Monad<M> => predicate.Bind(flag => flag ? then : M.Pure(unit)); This will work for any monad, `Option`, `List`, `Reader`, ... or anything that defines the trait. So types like `Option` are just pure data-types. They become monads when the Monad trait is implemented for them. The monad trait can be implemented for data-types and function-types. Reader, for example, has the Monad trait implemented for the function: Func<E, A> btw, monads also inherit behaviour from applicative and functor. The ability to lift pure values into the monad (a -> m a) is vital to making monads useful. This is `select` in LINQ, `pure` in Haskell's Applicative, and `Pure` in language-ext's Applicative [2]. [1] https://github.com/louthy/language-ext/blob/main/LanguageExt.Core/Traits/Monads/Monad/Monad.Trait.cs https://github.com/louthy/language-ext/blob/main/LanguageExt... [2] https://github.com/louthy/language-ext/blob/main/LanguageExt.Core/Traits/Applicative/Applicative.Trait.cs#L31 https://github.com/louthy/language-ext/blob/main/LanguageExt...