Struggling with implementing a Monad function





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







4















Recently, I'm playing around with Haskell monad and trying to learn about this concept.



Let's say there is a tree data type declared which can have multiple sub-trees.



data MyTree a = MyTree a [MyTree a]


And I'm trying to implement a function that returns "Nothing" if the tree contains any "Nothing" value in the tree. Else, extract all m value and returns a wrapped tree.



So the function type signature has the following.



check :: Monad m => MyTree (m a) -> m (MyTree a)


And here is my current implementation.



check (MyTree v ) = v >>= (v' -> return (MyTree v' ))
check (MyTree v (x:xs)) =
v >>= (v' -> check x >>= (t' -> return (MyTree v' [t'])))


I use a bind operator on v so that I can get a pure value of it. Then I call the "check" function recursively with the head value from the list. Finally, I wrap the final results.



I tested with some samples and got the following results.



> test1 = MyTree (Just 1) [MyTree (Just 2) [MyTree (Just 3) ]]
> check test1
Just (MyTree 1 [MyTree 2 [MyTree 3 ]])

> test2 = MyTree (Just 1) [MyTree (Just 2) , MyTree (Just 3) ]
> check test2
-- expected: Just (MyTree 1 [MyTree 2 , MyTree 3 ]
-- actual: Just (MyTree 1 [MyTree 2 ])


So, the current implementation has a problem when the input tree has multiple sub-trees. And I have realized that the problem is that I'm only using x but not xs. I wrapped my head around to think of the right approach and still figuring out. It will be very helpful if anyone has an idea for this.










share|improve this question




















  • 3





    As a hint, try writing an auxiliary function [m (MyTree a)] -> m [MyTree a] first (or use sequence from the libraries). Then think about how you can exploit that for xs. You will probably realize that you don't even need to handle the first element x in a special way, but you can directly use check (MyTree v xs) =....

    – chi
    Nov 21 '18 at 23:33













  • Thanks @chi. One more question! xs has a type [MyTree (m a)] and how do you feed that in an auxiliary function, [m (MyTree a)] -> m [MyTree a]? I'm getting it to the right way but bridging between these two is quite confusing.

    – ykdojo
    Nov 22 '18 at 2:07













  • That's correct, we need to turn [MyTree (m a)] into [m (MyTree a)]. We could use map f for that, for some f :: MyTree (m a) -> m (MyTree a). Do we have such a function?

    – chi
    Nov 22 '18 at 9:15











  • By "Nothing", do you mean the value Nothing :: Maybe a? Your function type should be MyTree (Maybe a) -> Maybe (MyTree a); no general constraint Monad m => is needed.

    – chepner
    Nov 22 '18 at 15:35


















4















Recently, I'm playing around with Haskell monad and trying to learn about this concept.



Let's say there is a tree data type declared which can have multiple sub-trees.



data MyTree a = MyTree a [MyTree a]


And I'm trying to implement a function that returns "Nothing" if the tree contains any "Nothing" value in the tree. Else, extract all m value and returns a wrapped tree.



So the function type signature has the following.



check :: Monad m => MyTree (m a) -> m (MyTree a)


And here is my current implementation.



check (MyTree v ) = v >>= (v' -> return (MyTree v' ))
check (MyTree v (x:xs)) =
v >>= (v' -> check x >>= (t' -> return (MyTree v' [t'])))


I use a bind operator on v so that I can get a pure value of it. Then I call the "check" function recursively with the head value from the list. Finally, I wrap the final results.



I tested with some samples and got the following results.



> test1 = MyTree (Just 1) [MyTree (Just 2) [MyTree (Just 3) ]]
> check test1
Just (MyTree 1 [MyTree 2 [MyTree 3 ]])

> test2 = MyTree (Just 1) [MyTree (Just 2) , MyTree (Just 3) ]
> check test2
-- expected: Just (MyTree 1 [MyTree 2 , MyTree 3 ]
-- actual: Just (MyTree 1 [MyTree 2 ])


So, the current implementation has a problem when the input tree has multiple sub-trees. And I have realized that the problem is that I'm only using x but not xs. I wrapped my head around to think of the right approach and still figuring out. It will be very helpful if anyone has an idea for this.










share|improve this question




















  • 3





    As a hint, try writing an auxiliary function [m (MyTree a)] -> m [MyTree a] first (or use sequence from the libraries). Then think about how you can exploit that for xs. You will probably realize that you don't even need to handle the first element x in a special way, but you can directly use check (MyTree v xs) =....

    – chi
    Nov 21 '18 at 23:33













  • Thanks @chi. One more question! xs has a type [MyTree (m a)] and how do you feed that in an auxiliary function, [m (MyTree a)] -> m [MyTree a]? I'm getting it to the right way but bridging between these two is quite confusing.

    – ykdojo
    Nov 22 '18 at 2:07













  • That's correct, we need to turn [MyTree (m a)] into [m (MyTree a)]. We could use map f for that, for some f :: MyTree (m a) -> m (MyTree a). Do we have such a function?

    – chi
    Nov 22 '18 at 9:15











  • By "Nothing", do you mean the value Nothing :: Maybe a? Your function type should be MyTree (Maybe a) -> Maybe (MyTree a); no general constraint Monad m => is needed.

    – chepner
    Nov 22 '18 at 15:35














4












4








4


1






Recently, I'm playing around with Haskell monad and trying to learn about this concept.



Let's say there is a tree data type declared which can have multiple sub-trees.



data MyTree a = MyTree a [MyTree a]


And I'm trying to implement a function that returns "Nothing" if the tree contains any "Nothing" value in the tree. Else, extract all m value and returns a wrapped tree.



So the function type signature has the following.



check :: Monad m => MyTree (m a) -> m (MyTree a)


And here is my current implementation.



check (MyTree v ) = v >>= (v' -> return (MyTree v' ))
check (MyTree v (x:xs)) =
v >>= (v' -> check x >>= (t' -> return (MyTree v' [t'])))


I use a bind operator on v so that I can get a pure value of it. Then I call the "check" function recursively with the head value from the list. Finally, I wrap the final results.



I tested with some samples and got the following results.



> test1 = MyTree (Just 1) [MyTree (Just 2) [MyTree (Just 3) ]]
> check test1
Just (MyTree 1 [MyTree 2 [MyTree 3 ]])

> test2 = MyTree (Just 1) [MyTree (Just 2) , MyTree (Just 3) ]
> check test2
-- expected: Just (MyTree 1 [MyTree 2 , MyTree 3 ]
-- actual: Just (MyTree 1 [MyTree 2 ])


So, the current implementation has a problem when the input tree has multiple sub-trees. And I have realized that the problem is that I'm only using x but not xs. I wrapped my head around to think of the right approach and still figuring out. It will be very helpful if anyone has an idea for this.










share|improve this question
















Recently, I'm playing around with Haskell monad and trying to learn about this concept.



Let's say there is a tree data type declared which can have multiple sub-trees.



data MyTree a = MyTree a [MyTree a]


And I'm trying to implement a function that returns "Nothing" if the tree contains any "Nothing" value in the tree. Else, extract all m value and returns a wrapped tree.



So the function type signature has the following.



check :: Monad m => MyTree (m a) -> m (MyTree a)


And here is my current implementation.



check (MyTree v ) = v >>= (v' -> return (MyTree v' ))
check (MyTree v (x:xs)) =
v >>= (v' -> check x >>= (t' -> return (MyTree v' [t'])))


I use a bind operator on v so that I can get a pure value of it. Then I call the "check" function recursively with the head value from the list. Finally, I wrap the final results.



I tested with some samples and got the following results.



> test1 = MyTree (Just 1) [MyTree (Just 2) [MyTree (Just 3) ]]
> check test1
Just (MyTree 1 [MyTree 2 [MyTree 3 ]])

> test2 = MyTree (Just 1) [MyTree (Just 2) , MyTree (Just 3) ]
> check test2
-- expected: Just (MyTree 1 [MyTree 2 , MyTree 3 ]
-- actual: Just (MyTree 1 [MyTree 2 ])


So, the current implementation has a problem when the input tree has multiple sub-trees. And I have realized that the problem is that I'm only using x but not xs. I wrapped my head around to think of the right approach and still figuring out. It will be very helpful if anyone has an idea for this.







haskell functional-programming monads






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 1:26









dfeuer

33.7k349133




33.7k349133










asked Nov 21 '18 at 23:23









ykdojoykdojo

254




254








  • 3





    As a hint, try writing an auxiliary function [m (MyTree a)] -> m [MyTree a] first (or use sequence from the libraries). Then think about how you can exploit that for xs. You will probably realize that you don't even need to handle the first element x in a special way, but you can directly use check (MyTree v xs) =....

    – chi
    Nov 21 '18 at 23:33













  • Thanks @chi. One more question! xs has a type [MyTree (m a)] and how do you feed that in an auxiliary function, [m (MyTree a)] -> m [MyTree a]? I'm getting it to the right way but bridging between these two is quite confusing.

    – ykdojo
    Nov 22 '18 at 2:07













  • That's correct, we need to turn [MyTree (m a)] into [m (MyTree a)]. We could use map f for that, for some f :: MyTree (m a) -> m (MyTree a). Do we have such a function?

    – chi
    Nov 22 '18 at 9:15











  • By "Nothing", do you mean the value Nothing :: Maybe a? Your function type should be MyTree (Maybe a) -> Maybe (MyTree a); no general constraint Monad m => is needed.

    – chepner
    Nov 22 '18 at 15:35














  • 3





    As a hint, try writing an auxiliary function [m (MyTree a)] -> m [MyTree a] first (or use sequence from the libraries). Then think about how you can exploit that for xs. You will probably realize that you don't even need to handle the first element x in a special way, but you can directly use check (MyTree v xs) =....

    – chi
    Nov 21 '18 at 23:33













  • Thanks @chi. One more question! xs has a type [MyTree (m a)] and how do you feed that in an auxiliary function, [m (MyTree a)] -> m [MyTree a]? I'm getting it to the right way but bridging between these two is quite confusing.

    – ykdojo
    Nov 22 '18 at 2:07













  • That's correct, we need to turn [MyTree (m a)] into [m (MyTree a)]. We could use map f for that, for some f :: MyTree (m a) -> m (MyTree a). Do we have such a function?

    – chi
    Nov 22 '18 at 9:15











  • By "Nothing", do you mean the value Nothing :: Maybe a? Your function type should be MyTree (Maybe a) -> Maybe (MyTree a); no general constraint Monad m => is needed.

    – chepner
    Nov 22 '18 at 15:35








3




3





As a hint, try writing an auxiliary function [m (MyTree a)] -> m [MyTree a] first (or use sequence from the libraries). Then think about how you can exploit that for xs. You will probably realize that you don't even need to handle the first element x in a special way, but you can directly use check (MyTree v xs) =....

– chi
Nov 21 '18 at 23:33







As a hint, try writing an auxiliary function [m (MyTree a)] -> m [MyTree a] first (or use sequence from the libraries). Then think about how you can exploit that for xs. You will probably realize that you don't even need to handle the first element x in a special way, but you can directly use check (MyTree v xs) =....

– chi
Nov 21 '18 at 23:33















Thanks @chi. One more question! xs has a type [MyTree (m a)] and how do you feed that in an auxiliary function, [m (MyTree a)] -> m [MyTree a]? I'm getting it to the right way but bridging between these two is quite confusing.

– ykdojo
Nov 22 '18 at 2:07







Thanks @chi. One more question! xs has a type [MyTree (m a)] and how do you feed that in an auxiliary function, [m (MyTree a)] -> m [MyTree a]? I'm getting it to the right way but bridging between these two is quite confusing.

– ykdojo
Nov 22 '18 at 2:07















That's correct, we need to turn [MyTree (m a)] into [m (MyTree a)]. We could use map f for that, for some f :: MyTree (m a) -> m (MyTree a). Do we have such a function?

– chi
Nov 22 '18 at 9:15





That's correct, we need to turn [MyTree (m a)] into [m (MyTree a)]. We could use map f for that, for some f :: MyTree (m a) -> m (MyTree a). Do we have such a function?

– chi
Nov 22 '18 at 9:15













By "Nothing", do you mean the value Nothing :: Maybe a? Your function type should be MyTree (Maybe a) -> Maybe (MyTree a); no general constraint Monad m => is needed.

– chepner
Nov 22 '18 at 15:35





By "Nothing", do you mean the value Nothing :: Maybe a? Your function type should be MyTree (Maybe a) -> Maybe (MyTree a); no general constraint Monad m => is needed.

– chepner
Nov 22 '18 at 15:35












1 Answer
1






active

oldest

votes


















6














Your check function is better known as a method of the Traversable class.



class (Functor t, Foldable t) => Traversable t where
-- The main method
traverse
:: Applicative f
=> (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f

-- An alternative
sequenceA
:: Applicative f
=> t (f a) -> f (t a)
sequenceA = traverse id

-- (Mostly) legacy methods
mapM
:: Monad m
=> (a -> m b) -> t a -> m (t b)
mapM = traverse

sequence
:: Monad m
=> t (m a) -> m (t a)
sequence = sequenceA


Specifically, check is sequence for MyTree. So we will get it if we write a Traversable MyTree instance. But let's first take a step back in two directions. Traversable is a subclass of both Functor and Foldable, and that is no coincidence. It's possible to implement both fmap and foldMap using traverse. But more to the point, the structures of fmap, foldMap and traverse tend to look almost identical! So let's start with those easier ones.



instance Functor MyTree where
fmap f (MyTree a ts) = MyTree (f a) _


What goes in that blank? We have a list of subtrees and we need to generate a new one, so a good bet is



  fmap f (MyTree a ts) = MyTree (f a) (fmap _ ts)


Now the blank has type MyTree a -> MyTree b, so we just call fmap recursively:



  fmap f (MyTree a ts) = MyTree (f a) (fmap (fmap f) ts)


And we're done. Now let's turn to Foldable.



foldMap f (MyTree a ts) = _


Well, we're going to need to apply f to a to get a value in the monoid, then fold up the subtrees and combine the results. This ends up looking quite a bit like fmap, as promised.



foldMap f (MyTree a ts) = f a <> foldMap (foldMap f) ts


So now we get to Traversable. It's going to be pretty similar to fmap, but we need to combine results using Applicative operations somewhat like we combined foldMap results using Monoid operations.



instance Traversable MyTree where
traverse f (MyTree a ts) = _


We have



a :: a
ts :: [MyTree a]
f :: a -> f b


Obviously, we're going to want to apply f to a. Following the pattern for fmap and foldMap, we're going to calculate traverse (traverse f) ts. So let's see where that gets us:



traverse f (MyTree a ts) = _ (f a) (traverse (traverse f) ts)


Now GHC will tell us that



_ :: f b -> f [MyTree b] -> f (MyTree b)


We need to take the b result from the first action and the [MyTree b] result from the second action and apply the MyTree constructor to put them together. We can do this using liftA2:



traverse f (MyTree a ts) = liftA2 MyTree (f a) (traverse (traverse f) ts)




Once you've gotten the hang of writing Functor, Foldable, and Traversable instances, doing so tends to get pretty dull. So GHC has an extension that lets the compiler write them for you.



{-# language DeriveTraversable #-}

module MyModule where

data MyTree a = MyTree a [MyTree a]
deriving (Functor, Foldable, Traversable)


And you're done.






share|improve this answer


























  • Thanks for the quick and useful answer. I really appreciate it! @DanielWagner

    – ykdojo
    Nov 22 '18 at 2:36












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53421838%2fstruggling-with-implementing-a-monad-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









6














Your check function is better known as a method of the Traversable class.



class (Functor t, Foldable t) => Traversable t where
-- The main method
traverse
:: Applicative f
=> (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f

-- An alternative
sequenceA
:: Applicative f
=> t (f a) -> f (t a)
sequenceA = traverse id

-- (Mostly) legacy methods
mapM
:: Monad m
=> (a -> m b) -> t a -> m (t b)
mapM = traverse

sequence
:: Monad m
=> t (m a) -> m (t a)
sequence = sequenceA


Specifically, check is sequence for MyTree. So we will get it if we write a Traversable MyTree instance. But let's first take a step back in two directions. Traversable is a subclass of both Functor and Foldable, and that is no coincidence. It's possible to implement both fmap and foldMap using traverse. But more to the point, the structures of fmap, foldMap and traverse tend to look almost identical! So let's start with those easier ones.



instance Functor MyTree where
fmap f (MyTree a ts) = MyTree (f a) _


What goes in that blank? We have a list of subtrees and we need to generate a new one, so a good bet is



  fmap f (MyTree a ts) = MyTree (f a) (fmap _ ts)


Now the blank has type MyTree a -> MyTree b, so we just call fmap recursively:



  fmap f (MyTree a ts) = MyTree (f a) (fmap (fmap f) ts)


And we're done. Now let's turn to Foldable.



foldMap f (MyTree a ts) = _


Well, we're going to need to apply f to a to get a value in the monoid, then fold up the subtrees and combine the results. This ends up looking quite a bit like fmap, as promised.



foldMap f (MyTree a ts) = f a <> foldMap (foldMap f) ts


So now we get to Traversable. It's going to be pretty similar to fmap, but we need to combine results using Applicative operations somewhat like we combined foldMap results using Monoid operations.



instance Traversable MyTree where
traverse f (MyTree a ts) = _


We have



a :: a
ts :: [MyTree a]
f :: a -> f b


Obviously, we're going to want to apply f to a. Following the pattern for fmap and foldMap, we're going to calculate traverse (traverse f) ts. So let's see where that gets us:



traverse f (MyTree a ts) = _ (f a) (traverse (traverse f) ts)


Now GHC will tell us that



_ :: f b -> f [MyTree b] -> f (MyTree b)


We need to take the b result from the first action and the [MyTree b] result from the second action and apply the MyTree constructor to put them together. We can do this using liftA2:



traverse f (MyTree a ts) = liftA2 MyTree (f a) (traverse (traverse f) ts)




Once you've gotten the hang of writing Functor, Foldable, and Traversable instances, doing so tends to get pretty dull. So GHC has an extension that lets the compiler write them for you.



{-# language DeriveTraversable #-}

module MyModule where

data MyTree a = MyTree a [MyTree a]
deriving (Functor, Foldable, Traversable)


And you're done.






share|improve this answer


























  • Thanks for the quick and useful answer. I really appreciate it! @DanielWagner

    – ykdojo
    Nov 22 '18 at 2:36
















6














Your check function is better known as a method of the Traversable class.



class (Functor t, Foldable t) => Traversable t where
-- The main method
traverse
:: Applicative f
=> (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f

-- An alternative
sequenceA
:: Applicative f
=> t (f a) -> f (t a)
sequenceA = traverse id

-- (Mostly) legacy methods
mapM
:: Monad m
=> (a -> m b) -> t a -> m (t b)
mapM = traverse

sequence
:: Monad m
=> t (m a) -> m (t a)
sequence = sequenceA


Specifically, check is sequence for MyTree. So we will get it if we write a Traversable MyTree instance. But let's first take a step back in two directions. Traversable is a subclass of both Functor and Foldable, and that is no coincidence. It's possible to implement both fmap and foldMap using traverse. But more to the point, the structures of fmap, foldMap and traverse tend to look almost identical! So let's start with those easier ones.



instance Functor MyTree where
fmap f (MyTree a ts) = MyTree (f a) _


What goes in that blank? We have a list of subtrees and we need to generate a new one, so a good bet is



  fmap f (MyTree a ts) = MyTree (f a) (fmap _ ts)


Now the blank has type MyTree a -> MyTree b, so we just call fmap recursively:



  fmap f (MyTree a ts) = MyTree (f a) (fmap (fmap f) ts)


And we're done. Now let's turn to Foldable.



foldMap f (MyTree a ts) = _


Well, we're going to need to apply f to a to get a value in the monoid, then fold up the subtrees and combine the results. This ends up looking quite a bit like fmap, as promised.



foldMap f (MyTree a ts) = f a <> foldMap (foldMap f) ts


So now we get to Traversable. It's going to be pretty similar to fmap, but we need to combine results using Applicative operations somewhat like we combined foldMap results using Monoid operations.



instance Traversable MyTree where
traverse f (MyTree a ts) = _


We have



a :: a
ts :: [MyTree a]
f :: a -> f b


Obviously, we're going to want to apply f to a. Following the pattern for fmap and foldMap, we're going to calculate traverse (traverse f) ts. So let's see where that gets us:



traverse f (MyTree a ts) = _ (f a) (traverse (traverse f) ts)


Now GHC will tell us that



_ :: f b -> f [MyTree b] -> f (MyTree b)


We need to take the b result from the first action and the [MyTree b] result from the second action and apply the MyTree constructor to put them together. We can do this using liftA2:



traverse f (MyTree a ts) = liftA2 MyTree (f a) (traverse (traverse f) ts)




Once you've gotten the hang of writing Functor, Foldable, and Traversable instances, doing so tends to get pretty dull. So GHC has an extension that lets the compiler write them for you.



{-# language DeriveTraversable #-}

module MyModule where

data MyTree a = MyTree a [MyTree a]
deriving (Functor, Foldable, Traversable)


And you're done.






share|improve this answer


























  • Thanks for the quick and useful answer. I really appreciate it! @DanielWagner

    – ykdojo
    Nov 22 '18 at 2:36














6












6








6







Your check function is better known as a method of the Traversable class.



class (Functor t, Foldable t) => Traversable t where
-- The main method
traverse
:: Applicative f
=> (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f

-- An alternative
sequenceA
:: Applicative f
=> t (f a) -> f (t a)
sequenceA = traverse id

-- (Mostly) legacy methods
mapM
:: Monad m
=> (a -> m b) -> t a -> m (t b)
mapM = traverse

sequence
:: Monad m
=> t (m a) -> m (t a)
sequence = sequenceA


Specifically, check is sequence for MyTree. So we will get it if we write a Traversable MyTree instance. But let's first take a step back in two directions. Traversable is a subclass of both Functor and Foldable, and that is no coincidence. It's possible to implement both fmap and foldMap using traverse. But more to the point, the structures of fmap, foldMap and traverse tend to look almost identical! So let's start with those easier ones.



instance Functor MyTree where
fmap f (MyTree a ts) = MyTree (f a) _


What goes in that blank? We have a list of subtrees and we need to generate a new one, so a good bet is



  fmap f (MyTree a ts) = MyTree (f a) (fmap _ ts)


Now the blank has type MyTree a -> MyTree b, so we just call fmap recursively:



  fmap f (MyTree a ts) = MyTree (f a) (fmap (fmap f) ts)


And we're done. Now let's turn to Foldable.



foldMap f (MyTree a ts) = _


Well, we're going to need to apply f to a to get a value in the monoid, then fold up the subtrees and combine the results. This ends up looking quite a bit like fmap, as promised.



foldMap f (MyTree a ts) = f a <> foldMap (foldMap f) ts


So now we get to Traversable. It's going to be pretty similar to fmap, but we need to combine results using Applicative operations somewhat like we combined foldMap results using Monoid operations.



instance Traversable MyTree where
traverse f (MyTree a ts) = _


We have



a :: a
ts :: [MyTree a]
f :: a -> f b


Obviously, we're going to want to apply f to a. Following the pattern for fmap and foldMap, we're going to calculate traverse (traverse f) ts. So let's see where that gets us:



traverse f (MyTree a ts) = _ (f a) (traverse (traverse f) ts)


Now GHC will tell us that



_ :: f b -> f [MyTree b] -> f (MyTree b)


We need to take the b result from the first action and the [MyTree b] result from the second action and apply the MyTree constructor to put them together. We can do this using liftA2:



traverse f (MyTree a ts) = liftA2 MyTree (f a) (traverse (traverse f) ts)




Once you've gotten the hang of writing Functor, Foldable, and Traversable instances, doing so tends to get pretty dull. So GHC has an extension that lets the compiler write them for you.



{-# language DeriveTraversable #-}

module MyModule where

data MyTree a = MyTree a [MyTree a]
deriving (Functor, Foldable, Traversable)


And you're done.






share|improve this answer















Your check function is better known as a method of the Traversable class.



class (Functor t, Foldable t) => Traversable t where
-- The main method
traverse
:: Applicative f
=> (a -> f b) -> t a -> f (t b)
traverse f = sequenceA . fmap f

-- An alternative
sequenceA
:: Applicative f
=> t (f a) -> f (t a)
sequenceA = traverse id

-- (Mostly) legacy methods
mapM
:: Monad m
=> (a -> m b) -> t a -> m (t b)
mapM = traverse

sequence
:: Monad m
=> t (m a) -> m (t a)
sequence = sequenceA


Specifically, check is sequence for MyTree. So we will get it if we write a Traversable MyTree instance. But let's first take a step back in two directions. Traversable is a subclass of both Functor and Foldable, and that is no coincidence. It's possible to implement both fmap and foldMap using traverse. But more to the point, the structures of fmap, foldMap and traverse tend to look almost identical! So let's start with those easier ones.



instance Functor MyTree where
fmap f (MyTree a ts) = MyTree (f a) _


What goes in that blank? We have a list of subtrees and we need to generate a new one, so a good bet is



  fmap f (MyTree a ts) = MyTree (f a) (fmap _ ts)


Now the blank has type MyTree a -> MyTree b, so we just call fmap recursively:



  fmap f (MyTree a ts) = MyTree (f a) (fmap (fmap f) ts)


And we're done. Now let's turn to Foldable.



foldMap f (MyTree a ts) = _


Well, we're going to need to apply f to a to get a value in the monoid, then fold up the subtrees and combine the results. This ends up looking quite a bit like fmap, as promised.



foldMap f (MyTree a ts) = f a <> foldMap (foldMap f) ts


So now we get to Traversable. It's going to be pretty similar to fmap, but we need to combine results using Applicative operations somewhat like we combined foldMap results using Monoid operations.



instance Traversable MyTree where
traverse f (MyTree a ts) = _


We have



a :: a
ts :: [MyTree a]
f :: a -> f b


Obviously, we're going to want to apply f to a. Following the pattern for fmap and foldMap, we're going to calculate traverse (traverse f) ts. So let's see where that gets us:



traverse f (MyTree a ts) = _ (f a) (traverse (traverse f) ts)


Now GHC will tell us that



_ :: f b -> f [MyTree b] -> f (MyTree b)


We need to take the b result from the first action and the [MyTree b] result from the second action and apply the MyTree constructor to put them together. We can do this using liftA2:



traverse f (MyTree a ts) = liftA2 MyTree (f a) (traverse (traverse f) ts)




Once you've gotten the hang of writing Functor, Foldable, and Traversable instances, doing so tends to get pretty dull. So GHC has an extension that lets the compiler write them for you.



{-# language DeriveTraversable #-}

module MyModule where

data MyTree a = MyTree a [MyTree a]
deriving (Functor, Foldable, Traversable)


And you're done.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 22 '18 at 1:32









Daniel Wagner

104k7161285




104k7161285










answered Nov 22 '18 at 0:34









dfeuerdfeuer

33.7k349133




33.7k349133













  • Thanks for the quick and useful answer. I really appreciate it! @DanielWagner

    – ykdojo
    Nov 22 '18 at 2:36



















  • Thanks for the quick and useful answer. I really appreciate it! @DanielWagner

    – ykdojo
    Nov 22 '18 at 2:36

















Thanks for the quick and useful answer. I really appreciate it! @DanielWagner

– ykdojo
Nov 22 '18 at 2:36





Thanks for the quick and useful answer. I really appreciate it! @DanielWagner

– ykdojo
Nov 22 '18 at 2:36




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53421838%2fstruggling-with-implementing-a-monad-function%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Guess what letter conforming each word

Port of Spain

Run scheduled task as local user group (not BUILTIN)