Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct fmap for a newtype that houses functions

So let's say I want to define a newtype that houses a function:

newtype Test m a = Test(m -> (a, m))

This could be used to house state of some sort.

Now let's say I would like to implement fmap for this newtype.

instance Functor (Test m) where
    --fmap :: (a -> b) -> Test m a -> Test m a -> b
    fmap f (Test f1) (Test f2) = ?

Since the newtype houses functions there's no way to use pattern matching to break f1 and f2 apart.

For instance I initially thought maybe I could pass the input value of f2 into the call f1 to yield a (a, m) tuple, but I don't think you can do that.
ie

tup = f1 (get input of f2)

Is anyone able to provide me with what concepts I'm missing to deal with this scenario or is this just not possible?

Thanks

UPDATE

Big thanks to Redu and Willem Van Onsem.

Looks like I was lacking in understanding of how to use the composition operator (.).

Basically the key here is use (.) to grab the first element of the tuple and then do a bunch of partial function definitions to get into the state needed by fmap. Here is my fmap implementation without using the library function. Purposefully verbose to help with understanding.

alterParamStateHelper :: (a -> b) -> (m -> a) -> m -> (b, m)
alterParamStateHelper f1 f2 m = (b, m)
  where 
    a = f2 e
    b = f1 a

alterParamState :: (a -> b) -> (m -> (a, m)) -> (m -> (b, m))
alterParamState f1 f2 = alterParamStateHelper f1 h1
  where
    h1 = fst . f2--m -> a

instance Functor (Test m) where
  -- fmap :: (a -> b) -> Test m a -> Test m b
  fmap f1 (Test f2) = Test (alterParamState f1 f2)
like image 731
mBrice1024 Avatar asked Oct 28 '19 17:10

mBrice1024


1 Answers

Since the newtype houses functions there's no way to use pattern matching to break f1 and f2 apart.

There is a problem with your fmap signature here. fmap has signature fmap :: Functor f => (a -> b) -> f a -> f b so if f ~ Test m, then the signature is fmap :: (a -> b) -> Test m a -> Test m b.

We thus can here define an fmap where we "post-process" the result of the function. We thus construct a new function that will use the old function to construct a 2-tuple (a, m), and then call f on the first item, such that we construct a tuple (b, m):

import Control.Arrow(first)

instance Functor (Test m) where
    fmap f (Test g) = Test (first f . g)
like image 140
Willem Van Onsem Avatar answered Oct 21 '22 17:10

Willem Van Onsem