mostly-adequate-guide
mostly-adequate-guide copied to clipboard
Incorrect type signature of findParam in Chapter 8
I have a feeling that the type signature in an en example from Chapter 8 is incorrect:
// params :: String -> [[String]]
var params = compose(toPairs, last, split('?'));
// findParam :: String -> IO Maybe [String]
var findParam = function(key) {
return map(compose(Maybe.of, filter(compose(eq(key), head)), params), url);
};
Since we're merely applying a filter to params
, wouldn't the type be [[String]]
, and after applying Maybe.of
, Maybe [[String]]
instead of Maybe [String]
?
yeah, the name 'findParams' is misleading. It implies that the result is maybe just one thing (a pair). This would make the typensignature correct. But the implementation of this method uses 'filter' which is always returning a Collection. Therefore Minh is correct.
Sent from my Tricorder
On 29.08.2016, at 22:17, Minh Nguyen [email protected] wrote:
I have a feeling that the type signature in an en example from Chapter 8 is incorrect:
// params :: String -> [[String]] var params = compose(toPairs, last, split('?'));
// findParam :: String -> IO Maybe [String] var findParam = function(key) { return map(compose(Maybe.of, filter(compose(eq(key), head)), params), url); }; Since we're merely applying a filter to params, wouldn't the type be [[String]], and after applying Maybe.of, Maybe [[String]] instead of Maybe [String]?
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.
There's indeed an issue with the combination of those functions. In the end, it'd make more sense to rely on a find
intermediate function with an appropriate signature.
// find :: (a -> Boolean) -> [a] -> Maybe a
const find = curry((p, xs) => compose(Maybe.of, head, filter(p))(xs));
// or
const find = curry((p, xs) => Maybe.of(xs.find(p)));
// findParam :: String -> IO (Maybe [String])
const findParam = key => {
const findOne = find(compose(eq(key), head));
return map(compose(findOne, params), url);
};
We could even go further and quickly introduce / pull from the annexe a Pair
type.
class Pair {
static of(x) {
return new Pair([x, x]);
}
static fromList(xs) {
return new Pair(xs);
}
constructor(xs) {
this.$value = xs;
}
inspect() {
return `Pair(${inspect(this.fst())}, ${inspect(this.snd())})`;
}
fst() {
return this.$value[0];
}
snd() {
return this.$value[1];
}
}
// fst :: Pair a -> a
const fst = p => p.fst();
// snd :: Pair a -> a
const snd = p => p.snd();
which leads to more comprehensive / richer type signatures:
// toPairs :: String -> [Pair String]
const toPairs = compose(map(compose(Pair.fromList, split('='))), split('&'));
// params :: String -> [Pair String]
const params = compose(toPairs, last, split('?'));
// find :: (a -> Boolean) -> [a] -> Maybe a
const find = curry((p, xs) => Maybe.of(xs.find(p)));
// findParam :: String -> IO (Maybe(Pair String))
const findParam = key => {
const findOne = find(compose(eq(key), fst));
return map(compose(findOne, params), url);
};
I believe only the signature should be corrected as initially suggested, and that the implementation should be left alone. Since a url param key is allowed to be duplicated (and there are use cases for such), findParam
should result in Maybe [[String]]
in order to collect all pairs with the same key.