Petras Purlys
Petras Purlys

Reputation: 1155

Binding to a monad that is inside a data structure in Haskell

Is there a way to define bind that only affects a part of a data structure?

For example, say we have a mock Computation data type that has a Name and a Result.

type Name          = String
data Error         = TimeOut | NotEnoughMemory | DivByZero
type Result a      = Either Error a
data Computation a = Computation Name (Result a)

Since the computation could fail but we might still be interested in its name, it can't be part of Result and must be part of Computation. On the other hand it would be also convenient to bind and validate results of Computations directly like you would do with a regular Either type. Is there a way to do that?

Upvotes: 2

Views: 81

Answers (2)

luqui
luqui

Reputation: 60463

TW monad transformers

I think you may want

type Computation = ExceptT Error (Writer Name)

-- in familiar types:
-- Computation a ⋍ (Either Error a, Name)

Notice that Name has to be a Monoid now. That makes sense, since

liftA2 (+) comp1 comp2

, which adds the results of two sub-computations, needs to also have a name. What the Writer component does is concatenates (with the monoid's <> -- so not necessarily just string concatenation) the names of the two sub-computations. Perhaps you would use, for example:

newtype Name = Name [String]
    deriving (Semigroup, Monoid)

You would probably also want a way to define the name of some computation:

name :: String -> Computation a -> Computation a
name n = mapExceptT (censor (const (Name [n])))

For example:

two :: Computation Int
two = name "two" $ pure 2

someComp :: Computation Int
someComp = name "two plus two" $ liftA2 (+) two two

Upvotes: 2

jberryman
jberryman

Reputation: 16645

No you probably can't define any useful instance Monad Computation, since you cannot define pure :: a -> Computation a from the Applicative class (which is a superclass of Monad); how would you instantiate the Name given just a value of type a?

It is a Functor though (and you can derive it automatically). With more context there might be a different abstraction that would be more useful.

Upvotes: 2

Related Questions