Is this a Functor or Monad?

前端 未结 3 1474
孤街浪徒
孤街浪徒 2021-01-12 18:17

I implemented my own Promise structure in C# and wanted to test the concept in Haskell so after some severe brain workouts (still very new to this) I produced



        
相关标签:
3条回答
  • 2021-01-12 18:51

    What you'll want to do is try to implement the instance for Functor and check if it conforms to the Functor Laws. Start with the instance:

    instance Functor (Promise f) where
        fmap f (PendingPromise g) = PendingPromise g
        fmap f (ResolvedPromise a) = ResolvedPromise (f a)
        fmap f BrokenPromise = BrokenPromise
    

    Does this conform to the Functor Laws? Since the cases for PendingPromise and BrokenPromise are always the identity, I'll exclude them for brevity:

    -- fmap id = id
    fmap id (ResolvedPromise a) = ResolvedPromise (id a) = ResolvedPromise a
    
    -- fmap (f . g) = fmap f . fmap g
    fmap (f . g) (ResolvedPromise a) = ResolvedPromise (f (g a))
    fmap f (fmap g (ResolvedPromise a)) = fmap f (ResolvedPromise (g a)) = ResolvedPromise (f (g a))
    

    So yes, it does conform to the Functor laws.

    Next, see if you can write the Applicative and Monad instances and prove that they conform to the respective laws. If you can write an instance that does, then your data type is a Monad, irrespective of the Future class.

    0 讨论(0)
  • 2021-01-12 18:53

    Here is the final code I came up with if its any use to someone. Promise is made an instance of the Functor class, which was the question, but also implements the Future class which to resolve the promise, maybe get its value, and make a new promise.

    data Promise a b =  Pending (a -> b) | Resolved b | Broken
    
    class Future p where
            resolve :: p a b -> a -> p a b
            getValue :: p a b -> Maybe b
            makePromise :: p a a
    
    instance Future Promise where
            resolve (Pending f) a = Resolved (f a)
            resolve (Resolved a) _ = Resolved a
            resolve Broken _ = Broken
    
            getValue (Resolved a) = Just a
            getValue (Pending _) = Nothing
            getValue Broken = Nothing
    
            makePromise = Pending id
    
    instance Functor (Promise a) where
            fmap f (Pending g) = Pending (f . g)
            fmap f (Resolved a) = Resolved (f a)
            fmap f Broken = Broken
    
    0 讨论(0)
  • 2021-01-12 18:55

    Yes, it is a monad. The easiest way to see this is observing Promise f a ≅ Maybe (Either f a), thus it's also isomorphic to the transformer equivalent which has an already-proven standard monad instance.

    type Promise' f = ErrorT f Maybe
    
    promise2Trafo :: Promise f a -> Promise' f a
    promise2Trafo (PendingPromise f) = ErrorT . Just $ Left f
    promise2Trafo (ResolvedPromise a) = ErrorT . Just $ Right a
    promise2Trafo BrokenPromise = ErrorT Nothing
    
    trafo2Promise :: Promise' f a -> Promise f a
    trafo2Promise = ... -- straightforward inverse of `promise2Trafo`
    
    instance Applicative Promise where
      pure = trafo2Promise . pure
      fp <*> xp = trafo2Promise $ promise2Trafo fp <*> promise2Trafo xp
    

    and so on.

    0 讨论(0)
提交回复
热议问题