Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - Automatic Monad instance

I'm trying to create my own data type, which will be part of Monad class, but

newtype Container a = Container a deriving Monad

gives me this error:

   * Can't make a derived instance of `Monad Container'
        (even with cunning GeneralizedNewtypeDeriving):
        cannot eta-reduce the representation type enough
    * In the newtype declaration for `Container'
   |
30 | newtype Container a = Container a deriving Monad

It works fine for other classes (Show for example), but not for Monad, so how can I convince ghci to instance my Container to Monad class?

Thanks

like image 215
Edward Grey Avatar asked Feb 28 '20 18:02

Edward Grey


People also ask

How do monads work Haskell?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

What is bind Haskell?

In Haskell, there is an operator bind, or ( >>= ) that allows for this monadic composition in a more elegant form similar to function composition.

Is list a monad Haskell?

Lists are a fundamental part of Haskell, and we've used them extensively before getting to this chapter. The novel insight is that the list type is a monad too! As monads, lists are used to model nondeterministic computations which may return an arbitrary number of results.

Is maybe a monad?

The Maybe sum type is a useful data type that forms a functor. Like many other useful functors, it also forms a monad.


1 Answers

It works fine for other classes (Show for example)

Only a fixed set of standard classes support deriving out-of-the-box:

In Haskell 98, the only derivable classes are Eq, Ord, Enum, Ix, Bounded, Read, and Show. Various language extensions extend this list.

--- The GHC User Manual

In particular Monad does not belong to that list, nor the extended one.

There are more extensions that generalize deriving to arbitrary classes, but they cannot be 100% automated. Someone somewhere has to specify how that deriving is to be done; depending on the class, the user may be required to carry the burden because there is information that fundamentally cannot be inferred.

In your case, the newtype Container is representationally equivalent to the Identity monad in the standard library, so you can use DerivingVia:

{-# LANGUAGE DerivingVia #-}
import Data.Functor.Identity

newtype Container a = Container a deriving (Functor, Applicative, Monad) via Identity

There is only one sensible instance in this very particular situation, but most of the time it's not easy to tell what the instance should be even if there is only one.

like image 169
Li-yao Xia Avatar answered Sep 27 '22 20:09

Li-yao Xia