Not with that exact type signature, no.
For example, if you choose type b = Double->Double
and your function [b]->b
is foldr (.) id
,
then your polymorphic function q
cannot use the value produced there to select from the pairs,
but I think that's misinterpreting your problem as seeking a specific type sig, rather than promoting/lifting
a means of selection from elements to pairs.
Solving the raw selection problem
If your original function is used simply to select an element from a list,
you could tell Haskell how to select between two, instead.
This solution is safe in the sense that it enforces using a selection from the original list or your fallback element,
by using a helper function b -> b -> Bool
, where True
indicates you prefer the first argument.
We can use that to select from a pair:
selectPair :: (a -> a -> Bool) -> (a,c) -> (a,c) -> (a,c)
selectPair f (a,c) (a',c')
| f a a' = (a,c)
| otherwise = (a',c')
And then fold to select from a list:
selectList :: (a -> a -> Bool) -> (a,c) -> [(a,c)] -> (a,c)
selectList f = foldr (selectPair f)
Notice that this doesn't require any instances on the type a
, so might be what you need in a general setting.
Solving the maximum problem
Of course (b -> b -> Bool)
feels very like >
from an Ord
instance, and your example used
a function suggesting maximum, but if you've got an Ord instance,
it would would be simplest to use import Data.List
and Data.Function
to do
safePairMaximum :: Ord b => (a, b) -> [(a, b)] -> (a, b)
safePairMaximum m bs = maximumBy (compare `on` snd) $ m:bs
This is a more basic, less cool version of part of hammar's solution.
Maybe you're stuck-with [b]->b, but do have equality on b
This gets as close to your type signature as I think is sensible whilst still solving your stated problem:
If using a selection function ::[b]->b
is crucial, then you'll need at least an Eq
context:
chooseLike :: Eq b => (a, b) -> ([b] -> b) -> ([(a, b)] -> (a, b))
chooseLike m selectb pairs = let wanted = selectb $ map snd pairs in
case filter ((==wanted).snd) pairs of
[] -> m
(p:_) -> p
(You can of course replace the Eq
context with a (b -> b -> Bool)
argument,
this time indicating equality.)
This isn't ideal, because you traverse the [b]
list seperately to the [(a,b)]
list, which seems inefficient.
Conclusion
Although I believe there's no useful function of exactly the type you specify,
there are various ways of solving the problem you stated. It was an interesting question, thanks.
[(a, b)]
list is empty, you'd need to make ana
out of thin air. You could writeq :: ([b] -> b) -> ([(a, b)] -> Maybe (a, b))
, though. – scvalexundefined
etc. are ugly and a bad idea, but legal. – user395760q :: (a, b) -> ([b] -> b) -> ([(a, b)] -> (a, b))
I'm still stuck. – Matt Fenwick[a] -> [a]
operate on[(a,Int)]
? – hammar