How do I derive the type for this function:
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
add a comment |
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
add a comment |
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
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
haskell types composition
asked Feb 7 at 8:20
Cameron BallCameron Ball
1,89031424
1,89031424
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
It helps to do two things before everything else:
- put explicit parentheses so that
x->y->z
becomesx->(y->z)
- 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.
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 ofzip
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
add a comment |
(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)]
add a comment |
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)] )
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
It helps to do two things before everything else:
- put explicit parentheses so that
x->y->z
becomesx->(y->z)
- 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.
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 ofzip
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
add a comment |
It helps to do two things before everything else:
- put explicit parentheses so that
x->y->z
becomesx->(y->z)
- 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.
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 ofzip
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
add a comment |
It helps to do two things before everything else:
- put explicit parentheses so that
x->y->z
becomesx->(y->z)
- 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.
It helps to do two things before everything else:
- put explicit parentheses so that
x->y->z
becomesx->(y->z)
- 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.
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 ofzip
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
add a comment |
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 ofzip
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
add a comment |
(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)]
add a comment |
(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)]
add a comment |
(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)]
(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)]
edited Feb 7 at 9:38
answered Feb 7 at 8:58
Bartek BanachewiczBartek Banachewicz
30.6k566106
30.6k566106
add a comment |
add a comment |
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)] )
add a comment |
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)] )
add a comment |
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)] )
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)] )
edited Feb 7 at 19:14
answered Feb 7 at 9:41
Will NessWill Ness
46.1k468126
46.1k468126
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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