How do I derive the type for this function:












14















I'm trying to get better at playing "type tetris". I have the functions:



(=<<) :: Monad m => (a -> m b) -> m a -> m b
zip :: [a] -> [b] -> [(a, b)]


And GHCi tells me:



(zip =<<) :: ([b] -> [a]) -> [b] -> [(a, b)]


I'm having a hard time figuring out how to arrive at that final signature from the first two. My intuition (for lack of a better word) is saying that the first argument of =<< namely a -> mb is somehow reconciled against the signature of zip, and then it should all fall out from that. But I can't understand how to make that leap. Can it be broken down in to a series of easy to follow steps?










share|improve this question



























    14















    I'm trying to get better at playing "type tetris". I have the functions:



    (=<<) :: Monad m => (a -> m b) -> m a -> m b
    zip :: [a] -> [b] -> [(a, b)]


    And GHCi tells me:



    (zip =<<) :: ([b] -> [a]) -> [b] -> [(a, b)]


    I'm having a hard time figuring out how to arrive at that final signature from the first two. My intuition (for lack of a better word) is saying that the first argument of =<< namely a -> mb is somehow reconciled against the signature of zip, and then it should all fall out from that. But I can't understand how to make that leap. Can it be broken down in to a series of easy to follow steps?










    share|improve this question

























      14












      14








      14


      1






      I'm trying to get better at playing "type tetris". I have the functions:



      (=<<) :: Monad m => (a -> m b) -> m a -> m b
      zip :: [a] -> [b] -> [(a, b)]


      And GHCi tells me:



      (zip =<<) :: ([b] -> [a]) -> [b] -> [(a, b)]


      I'm having a hard time figuring out how to arrive at that final signature from the first two. My intuition (for lack of a better word) is saying that the first argument of =<< namely a -> mb is somehow reconciled against the signature of zip, and then it should all fall out from that. But I can't understand how to make that leap. Can it be broken down in to a series of easy to follow steps?










      share|improve this question














      I'm trying to get better at playing "type tetris". I have the functions:



      (=<<) :: Monad m => (a -> m b) -> m a -> m b
      zip :: [a] -> [b] -> [(a, b)]


      And GHCi tells me:



      (zip =<<) :: ([b] -> [a]) -> [b] -> [(a, b)]


      I'm having a hard time figuring out how to arrive at that final signature from the first two. My intuition (for lack of a better word) is saying that the first argument of =<< namely a -> mb is somehow reconciled against the signature of zip, and then it should all fall out from that. But I can't understand how to make that leap. Can it be broken down in to a series of easy to follow steps?







      haskell types composition






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Feb 7 at 8:20









      Cameron BallCameron Ball

      1,89031424




      1,89031424
























          3 Answers
          3






          active

          oldest

          votes


















          7














          It helps to do two things before everything else:




          1. put explicit parentheses so that x->y->z becomes x->(y->z)

          2. rename type variables so that there are no clashes


          Wit this in mind let's rewrite the types



          (=<<) :: Monad m => (a -> m b) -> (m a -> m b)
          zip :: [x] -> ([y] -> [(x, y)])


          Now match the types. The first argument to =<< is zip, so (a -> m b) is the same as [x] -> ([y] -> [(x, y)]).



          a          ->        m b
          [x] -> ([y] -> [(x, y)])


          So a is [x] and m b is ([y] -> [(x, y)]). Rewriting -> in prefix notation, we get -> [y] [(x, y)], which is the same as (-> [y]) [(x, y)].



          m             b
          (-> [y]) [(x, y)]


          So m is (-> [y]) (which is a monad indeed) and b is [(x, y)].



          So now we know what is a, what is b and what is m. Let's rewrite (m a -> m b) in these terms:



          (m            a)          ->          (m            b)
          ((-> [y]) [x]) -> ((-> [y]) [(x, y)])


          Rewriting in the infix style again, we get



          ([y] -> [x])              ->          ([y] -> [(x, y)])


          which is, up to variable names, is the same answer GHC is giving you.






          share|improve this answer
























          • There are some great answers here, but this was the one that caused the penny to drop for me. For some reason I thought the signature of zip should completely replace that of (a -> m b) - when instead I should have been thinking of the signatures as being equal to each other and solving that way.

            – Cameron Ball
            Feb 8 at 3:02



















          8














          (zip =<<) is equivalent to (>>= zip), which makes it perhaps a bit more readable. Either way, zip occupies the (a -> m b) slot in those functions, as you've correctly observed.



          One more intuitive transformation to make is thinking about the arity of =<<. It "takes" two parameters, so if we apply it to one, we should only be left with one more. Hence, the signature ([b] -> [a]) -> [b] -> [(a, b)] is an unary function!



          (zip =<<) :: ([b] -> [a]) -> ([b] -> [(a, b)])
          ------------ -----------------
          m a' m b'


          So what's m? The Monad instance exists for functions (r ->) (or, alternatively, (->) r). So in this case r :: [b] (and thus m :: ([b] ->)), a' :: [a] and b' :: [(a, b)].



          Consequently, zip fits just as we asserted at the beginning:



          a'  -> m b'                    -- substitute [(a,b)] for b'
          a' -> m [(a, b)] -- substitute [a] for a'
          [a] -> m [(a, b)] -- substitute ([b] ->) for m
          [a] -> ([b] -> [(a,b)])

          [a] -> [b] -> [(a,b)]





          share|improve this answer

































            3














            You just write them down one under another, with vertical alignment as an aid, while renaming the type variables consistently so there's no accidental capture:



            (=<<) :: Monad m => (a1  ->     m    b1       ) -> m a1 -> m b1
            zip :: [a] -> ([b] -> [(a, b)])
            [a] -> ([b] ->) [(a, b)]
            [a] -> (->) [b] [(a, b)]
            -----------------------------------------------------------
            a1 ~ [a] , m ~ (->) [b] , b1 ~ [(a, b)] (*)
            -----------------------------------------------------------
            (zip =<<) :: Monad m => m a1 -> m b1
            ((->) [b]) a1 -> ((->) [b]) b1
            ([b] -> a1) -> ([b] -> b1)
            ([b] -> [a]) -> ([b] -> [(a, b)])
            ([b] -> [a]) -> [b] -> [(a, b)]


            provided that Monad ((->) [b]) instance exists. Which it does:



            > :i Monad
            class Monad (m :: * -> *) where
            .......
            instance Monad ((->) r) -- Defined in `GHC.Base'


            If we follow the types in the specific case of function monad, we can see that (g =<< f) x == g (f x) x, and so



            (zip =<<) f xs = zip (f xs) xs


            from which it's easier to see its type's meaning.





            (*) is the substitution resulting from the successful unification of the types a1 -> m b1 and [a] -> [b] -> [(a, b)] (which is [a] -> ([b] -> [(a, b)]), when fully parenthesized, because ->s in types associate to the right). Or in fully prefix form,



                (->)  a1   ( m            b1       )
            (->) [a] ( ((->) [b]) [(a, b)] )





            share|improve this answer

























              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%2f54568993%2fhow-do-i-derive-the-type-for-this-function%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              7














              It helps to do two things before everything else:




              1. put explicit parentheses so that x->y->z becomes x->(y->z)

              2. rename type variables so that there are no clashes


              Wit this in mind let's rewrite the types



              (=<<) :: Monad m => (a -> m b) -> (m a -> m b)
              zip :: [x] -> ([y] -> [(x, y)])


              Now match the types. The first argument to =<< is zip, so (a -> m b) is the same as [x] -> ([y] -> [(x, y)]).



              a          ->        m b
              [x] -> ([y] -> [(x, y)])


              So a is [x] and m b is ([y] -> [(x, y)]). Rewriting -> in prefix notation, we get -> [y] [(x, y)], which is the same as (-> [y]) [(x, y)].



              m             b
              (-> [y]) [(x, y)]


              So m is (-> [y]) (which is a monad indeed) and b is [(x, y)].



              So now we know what is a, what is b and what is m. Let's rewrite (m a -> m b) in these terms:



              (m            a)          ->          (m            b)
              ((-> [y]) [x]) -> ((-> [y]) [(x, y)])


              Rewriting in the infix style again, we get



              ([y] -> [x])              ->          ([y] -> [(x, y)])


              which is, up to variable names, is the same answer GHC is giving you.






              share|improve this answer
























              • There are some great answers here, but this was the one that caused the penny to drop for me. For some reason I thought the signature of zip should completely replace that of (a -> m b) - when instead I should have been thinking of the signatures as being equal to each other and solving that way.

                – Cameron Ball
                Feb 8 at 3:02
















              7














              It helps to do two things before everything else:




              1. put explicit parentheses so that x->y->z becomes x->(y->z)

              2. rename type variables so that there are no clashes


              Wit this in mind let's rewrite the types



              (=<<) :: Monad m => (a -> m b) -> (m a -> m b)
              zip :: [x] -> ([y] -> [(x, y)])


              Now match the types. The first argument to =<< is zip, so (a -> m b) is the same as [x] -> ([y] -> [(x, y)]).



              a          ->        m b
              [x] -> ([y] -> [(x, y)])


              So a is [x] and m b is ([y] -> [(x, y)]). Rewriting -> in prefix notation, we get -> [y] [(x, y)], which is the same as (-> [y]) [(x, y)].



              m             b
              (-> [y]) [(x, y)]


              So m is (-> [y]) (which is a monad indeed) and b is [(x, y)].



              So now we know what is a, what is b and what is m. Let's rewrite (m a -> m b) in these terms:



              (m            a)          ->          (m            b)
              ((-> [y]) [x]) -> ((-> [y]) [(x, y)])


              Rewriting in the infix style again, we get



              ([y] -> [x])              ->          ([y] -> [(x, y)])


              which is, up to variable names, is the same answer GHC is giving you.






              share|improve this answer
























              • There are some great answers here, but this was the one that caused the penny to drop for me. For some reason I thought the signature of zip should completely replace that of (a -> m b) - when instead I should have been thinking of the signatures as being equal to each other and solving that way.

                – Cameron Ball
                Feb 8 at 3:02














              7












              7








              7







              It helps to do two things before everything else:




              1. put explicit parentheses so that x->y->z becomes x->(y->z)

              2. rename type variables so that there are no clashes


              Wit this in mind let's rewrite the types



              (=<<) :: Monad m => (a -> m b) -> (m a -> m b)
              zip :: [x] -> ([y] -> [(x, y)])


              Now match the types. The first argument to =<< is zip, so (a -> m b) is the same as [x] -> ([y] -> [(x, y)]).



              a          ->        m b
              [x] -> ([y] -> [(x, y)])


              So a is [x] and m b is ([y] -> [(x, y)]). Rewriting -> in prefix notation, we get -> [y] [(x, y)], which is the same as (-> [y]) [(x, y)].



              m             b
              (-> [y]) [(x, y)]


              So m is (-> [y]) (which is a monad indeed) and b is [(x, y)].



              So now we know what is a, what is b and what is m. Let's rewrite (m a -> m b) in these terms:



              (m            a)          ->          (m            b)
              ((-> [y]) [x]) -> ((-> [y]) [(x, y)])


              Rewriting in the infix style again, we get



              ([y] -> [x])              ->          ([y] -> [(x, y)])


              which is, up to variable names, is the same answer GHC is giving you.






              share|improve this answer













              It helps to do two things before everything else:




              1. put explicit parentheses so that x->y->z becomes x->(y->z)

              2. rename type variables so that there are no clashes


              Wit this in mind let's rewrite the types



              (=<<) :: Monad m => (a -> m b) -> (m a -> m b)
              zip :: [x] -> ([y] -> [(x, y)])


              Now match the types. The first argument to =<< is zip, so (a -> m b) is the same as [x] -> ([y] -> [(x, y)]).



              a          ->        m b
              [x] -> ([y] -> [(x, y)])


              So a is [x] and m b is ([y] -> [(x, y)]). Rewriting -> in prefix notation, we get -> [y] [(x, y)], which is the same as (-> [y]) [(x, y)].



              m             b
              (-> [y]) [(x, y)]


              So m is (-> [y]) (which is a monad indeed) and b is [(x, y)].



              So now we know what is a, what is b and what is m. Let's rewrite (m a -> m b) in these terms:



              (m            a)          ->          (m            b)
              ((-> [y]) [x]) -> ((-> [y]) [(x, y)])


              Rewriting in the infix style again, we get



              ([y] -> [x])              ->          ([y] -> [(x, y)])


              which is, up to variable names, is the same answer GHC is giving you.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Feb 7 at 9:25









              n.m.n.m.

              72.9k882168




              72.9k882168













              • There are some great answers here, but this was the one that caused the penny to drop for me. For some reason I thought the signature of zip should completely replace that of (a -> m b) - when instead I should have been thinking of the signatures as being equal to each other and solving that way.

                – Cameron Ball
                Feb 8 at 3:02



















              • There are some great answers here, but this was the one that caused the penny to drop for me. For some reason I thought the signature of zip should completely replace that of (a -> m b) - when instead I should have been thinking of the signatures as being equal to each other and solving that way.

                – Cameron Ball
                Feb 8 at 3:02

















              There are some great answers here, but this was the one that caused the penny to drop for me. For some reason I thought the signature of zip should completely replace that of (a -> m b) - when instead I should have been thinking of the signatures as being equal to each other and solving that way.

              – Cameron Ball
              Feb 8 at 3:02





              There are some great answers here, but this was the one that caused the penny to drop for me. For some reason I thought the signature of zip should completely replace that of (a -> m b) - when instead I should have been thinking of the signatures as being equal to each other and solving that way.

              – Cameron Ball
              Feb 8 at 3:02













              8














              (zip =<<) is equivalent to (>>= zip), which makes it perhaps a bit more readable. Either way, zip occupies the (a -> m b) slot in those functions, as you've correctly observed.



              One more intuitive transformation to make is thinking about the arity of =<<. It "takes" two parameters, so if we apply it to one, we should only be left with one more. Hence, the signature ([b] -> [a]) -> [b] -> [(a, b)] is an unary function!



              (zip =<<) :: ([b] -> [a]) -> ([b] -> [(a, b)])
              ------------ -----------------
              m a' m b'


              So what's m? The Monad instance exists for functions (r ->) (or, alternatively, (->) r). So in this case r :: [b] (and thus m :: ([b] ->)), a' :: [a] and b' :: [(a, b)].



              Consequently, zip fits just as we asserted at the beginning:



              a'  -> m b'                    -- substitute [(a,b)] for b'
              a' -> m [(a, b)] -- substitute [a] for a'
              [a] -> m [(a, b)] -- substitute ([b] ->) for m
              [a] -> ([b] -> [(a,b)])

              [a] -> [b] -> [(a,b)]





              share|improve this answer






























                8














                (zip =<<) is equivalent to (>>= zip), which makes it perhaps a bit more readable. Either way, zip occupies the (a -> m b) slot in those functions, as you've correctly observed.



                One more intuitive transformation to make is thinking about the arity of =<<. It "takes" two parameters, so if we apply it to one, we should only be left with one more. Hence, the signature ([b] -> [a]) -> [b] -> [(a, b)] is an unary function!



                (zip =<<) :: ([b] -> [a]) -> ([b] -> [(a, b)])
                ------------ -----------------
                m a' m b'


                So what's m? The Monad instance exists for functions (r ->) (or, alternatively, (->) r). So in this case r :: [b] (and thus m :: ([b] ->)), a' :: [a] and b' :: [(a, b)].



                Consequently, zip fits just as we asserted at the beginning:



                a'  -> m b'                    -- substitute [(a,b)] for b'
                a' -> m [(a, b)] -- substitute [a] for a'
                [a] -> m [(a, b)] -- substitute ([b] ->) for m
                [a] -> ([b] -> [(a,b)])

                [a] -> [b] -> [(a,b)]





                share|improve this answer




























                  8












                  8








                  8







                  (zip =<<) is equivalent to (>>= zip), which makes it perhaps a bit more readable. Either way, zip occupies the (a -> m b) slot in those functions, as you've correctly observed.



                  One more intuitive transformation to make is thinking about the arity of =<<. It "takes" two parameters, so if we apply it to one, we should only be left with one more. Hence, the signature ([b] -> [a]) -> [b] -> [(a, b)] is an unary function!



                  (zip =<<) :: ([b] -> [a]) -> ([b] -> [(a, b)])
                  ------------ -----------------
                  m a' m b'


                  So what's m? The Monad instance exists for functions (r ->) (or, alternatively, (->) r). So in this case r :: [b] (and thus m :: ([b] ->)), a' :: [a] and b' :: [(a, b)].



                  Consequently, zip fits just as we asserted at the beginning:



                  a'  -> m b'                    -- substitute [(a,b)] for b'
                  a' -> m [(a, b)] -- substitute [a] for a'
                  [a] -> m [(a, b)] -- substitute ([b] ->) for m
                  [a] -> ([b] -> [(a,b)])

                  [a] -> [b] -> [(a,b)]





                  share|improve this answer















                  (zip =<<) is equivalent to (>>= zip), which makes it perhaps a bit more readable. Either way, zip occupies the (a -> m b) slot in those functions, as you've correctly observed.



                  One more intuitive transformation to make is thinking about the arity of =<<. It "takes" two parameters, so if we apply it to one, we should only be left with one more. Hence, the signature ([b] -> [a]) -> [b] -> [(a, b)] is an unary function!



                  (zip =<<) :: ([b] -> [a]) -> ([b] -> [(a, b)])
                  ------------ -----------------
                  m a' m b'


                  So what's m? The Monad instance exists for functions (r ->) (or, alternatively, (->) r). So in this case r :: [b] (and thus m :: ([b] ->)), a' :: [a] and b' :: [(a, b)].



                  Consequently, zip fits just as we asserted at the beginning:



                  a'  -> m b'                    -- substitute [(a,b)] for b'
                  a' -> m [(a, b)] -- substitute [a] for a'
                  [a] -> m [(a, b)] -- substitute ([b] ->) for m
                  [a] -> ([b] -> [(a,b)])

                  [a] -> [b] -> [(a,b)]






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Feb 7 at 9:38

























                  answered Feb 7 at 8:58









                  Bartek BanachewiczBartek Banachewicz

                  30.6k566106




                  30.6k566106























                      3














                      You just write them down one under another, with vertical alignment as an aid, while renaming the type variables consistently so there's no accidental capture:



                      (=<<) :: Monad m => (a1  ->     m    b1       ) -> m a1 -> m b1
                      zip :: [a] -> ([b] -> [(a, b)])
                      [a] -> ([b] ->) [(a, b)]
                      [a] -> (->) [b] [(a, b)]
                      -----------------------------------------------------------
                      a1 ~ [a] , m ~ (->) [b] , b1 ~ [(a, b)] (*)
                      -----------------------------------------------------------
                      (zip =<<) :: Monad m => m a1 -> m b1
                      ((->) [b]) a1 -> ((->) [b]) b1
                      ([b] -> a1) -> ([b] -> b1)
                      ([b] -> [a]) -> ([b] -> [(a, b)])
                      ([b] -> [a]) -> [b] -> [(a, b)]


                      provided that Monad ((->) [b]) instance exists. Which it does:



                      > :i Monad
                      class Monad (m :: * -> *) where
                      .......
                      instance Monad ((->) r) -- Defined in `GHC.Base'


                      If we follow the types in the specific case of function monad, we can see that (g =<< f) x == g (f x) x, and so



                      (zip =<<) f xs = zip (f xs) xs


                      from which it's easier to see its type's meaning.





                      (*) is the substitution resulting from the successful unification of the types a1 -> m b1 and [a] -> [b] -> [(a, b)] (which is [a] -> ([b] -> [(a, b)]), when fully parenthesized, because ->s in types associate to the right). Or in fully prefix form,



                          (->)  a1   ( m            b1       )
                      (->) [a] ( ((->) [b]) [(a, b)] )





                      share|improve this answer






























                        3














                        You just write them down one under another, with vertical alignment as an aid, while renaming the type variables consistently so there's no accidental capture:



                        (=<<) :: Monad m => (a1  ->     m    b1       ) -> m a1 -> m b1
                        zip :: [a] -> ([b] -> [(a, b)])
                        [a] -> ([b] ->) [(a, b)]
                        [a] -> (->) [b] [(a, b)]
                        -----------------------------------------------------------
                        a1 ~ [a] , m ~ (->) [b] , b1 ~ [(a, b)] (*)
                        -----------------------------------------------------------
                        (zip =<<) :: Monad m => m a1 -> m b1
                        ((->) [b]) a1 -> ((->) [b]) b1
                        ([b] -> a1) -> ([b] -> b1)
                        ([b] -> [a]) -> ([b] -> [(a, b)])
                        ([b] -> [a]) -> [b] -> [(a, b)]


                        provided that Monad ((->) [b]) instance exists. Which it does:



                        > :i Monad
                        class Monad (m :: * -> *) where
                        .......
                        instance Monad ((->) r) -- Defined in `GHC.Base'


                        If we follow the types in the specific case of function monad, we can see that (g =<< f) x == g (f x) x, and so



                        (zip =<<) f xs = zip (f xs) xs


                        from which it's easier to see its type's meaning.





                        (*) is the substitution resulting from the successful unification of the types a1 -> m b1 and [a] -> [b] -> [(a, b)] (which is [a] -> ([b] -> [(a, b)]), when fully parenthesized, because ->s in types associate to the right). Or in fully prefix form,



                            (->)  a1   ( m            b1       )
                        (->) [a] ( ((->) [b]) [(a, b)] )





                        share|improve this answer




























                          3












                          3








                          3







                          You just write them down one under another, with vertical alignment as an aid, while renaming the type variables consistently so there's no accidental capture:



                          (=<<) :: Monad m => (a1  ->     m    b1       ) -> m a1 -> m b1
                          zip :: [a] -> ([b] -> [(a, b)])
                          [a] -> ([b] ->) [(a, b)]
                          [a] -> (->) [b] [(a, b)]
                          -----------------------------------------------------------
                          a1 ~ [a] , m ~ (->) [b] , b1 ~ [(a, b)] (*)
                          -----------------------------------------------------------
                          (zip =<<) :: Monad m => m a1 -> m b1
                          ((->) [b]) a1 -> ((->) [b]) b1
                          ([b] -> a1) -> ([b] -> b1)
                          ([b] -> [a]) -> ([b] -> [(a, b)])
                          ([b] -> [a]) -> [b] -> [(a, b)]


                          provided that Monad ((->) [b]) instance exists. Which it does:



                          > :i Monad
                          class Monad (m :: * -> *) where
                          .......
                          instance Monad ((->) r) -- Defined in `GHC.Base'


                          If we follow the types in the specific case of function monad, we can see that (g =<< f) x == g (f x) x, and so



                          (zip =<<) f xs = zip (f xs) xs


                          from which it's easier to see its type's meaning.





                          (*) is the substitution resulting from the successful unification of the types a1 -> m b1 and [a] -> [b] -> [(a, b)] (which is [a] -> ([b] -> [(a, b)]), when fully parenthesized, because ->s in types associate to the right). Or in fully prefix form,



                              (->)  a1   ( m            b1       )
                          (->) [a] ( ((->) [b]) [(a, b)] )





                          share|improve this answer















                          You just write them down one under another, with vertical alignment as an aid, while renaming the type variables consistently so there's no accidental capture:



                          (=<<) :: Monad m => (a1  ->     m    b1       ) -> m a1 -> m b1
                          zip :: [a] -> ([b] -> [(a, b)])
                          [a] -> ([b] ->) [(a, b)]
                          [a] -> (->) [b] [(a, b)]
                          -----------------------------------------------------------
                          a1 ~ [a] , m ~ (->) [b] , b1 ~ [(a, b)] (*)
                          -----------------------------------------------------------
                          (zip =<<) :: Monad m => m a1 -> m b1
                          ((->) [b]) a1 -> ((->) [b]) b1
                          ([b] -> a1) -> ([b] -> b1)
                          ([b] -> [a]) -> ([b] -> [(a, b)])
                          ([b] -> [a]) -> [b] -> [(a, b)]


                          provided that Monad ((->) [b]) instance exists. Which it does:



                          > :i Monad
                          class Monad (m :: * -> *) where
                          .......
                          instance Monad ((->) r) -- Defined in `GHC.Base'


                          If we follow the types in the specific case of function monad, we can see that (g =<< f) x == g (f x) x, and so



                          (zip =<<) f xs = zip (f xs) xs


                          from which it's easier to see its type's meaning.





                          (*) is the substitution resulting from the successful unification of the types a1 -> m b1 and [a] -> [b] -> [(a, b)] (which is [a] -> ([b] -> [(a, b)]), when fully parenthesized, because ->s in types associate to the right). Or in fully prefix form,



                              (->)  a1   ( m            b1       )
                          (->) [a] ( ((->) [b]) [(a, b)] )






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Feb 7 at 19:14

























                          answered Feb 7 at 9:41









                          Will NessWill Ness

                          46.1k468126




                          46.1k468126






























                              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%2f54568993%2fhow-do-i-derive-the-type-for-this-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

                              How do I know what Microsoft account the skydrive app is syncing to?

                              When does type information flow backwards in C++?

                              Grease: Live!