I'll just say I'm not even sure if this is possible; it is by far the most generic thing I've tried doing in Haskell. I'm trying to make a more generic version of the applyFunc
found in https://stackoverflow.com/a/58890226/3096687:
newtype SummaryFun t a = SummaryFun (t a -> a)
applyRecFun :: (Traversable t, _) => Record (SummaryFun t) _ -> t r -> r
applyRecFun func recs =
let recs_NP :: t (NP I _) -- a list of n-ary products. I is an identity functor
recs_NP = toNP . toRecord <$> recs
listrecs_NP :: t (NP t _) -- turn every component into a singleton list
listrecs_NP = liftA_NP (\(I x) -> pure x) <$> recs_NP
listrec_NP :: NP t _ -- a single n-ary product where each component is a list
listrec_NP = mconcat listrecs_NP
func_NP :: NP (SummaryFun t) _ -- turn the function record into a n-ary prod
func_NP = toNP func
resultRec_NP_I :: NP I _ -- apply the functions to each list component
resultRec_NP_I = liftA2_NP (\(SummaryFun f) vs -> I (f vs)) func_NP listrec_NP
in fromRecord . fromNP $ resultRec_NP_I -- go back to the nominal record Rec
The first issue being run into is:
• Can't quantify over ‘t’
bound by the partial type signature: recs_NP :: t (NP I _)
And similar errors occur elsewhere.
I can't be sure this will fix everything, because it's very hard to reproduce your problem: it requires a lot of packages and imports that I just don't have the time to set up (hint: in the future, try to reduce your problems to minimal reproducible examples before posting). But I'm going to post this anyway, because I can see at least one problem, and it seems to be related to the error message.
The problem is that t
on the first line is not the same as t
on the third line, and they are both different from the t
on the fifth line. And so on, for all type signatures involving t
.
By default, in Haskell2010 every type variable's scope is only the type signature in which it's introduced. If you use the same letter in another type signature, it will signify a completely separate type, despite looking identical to the human eye.
To specify that you actually mean t
to be the same everywhere, you have to use forall
in the top type signature:
applyRecFun :: forall t. (Traversable t, _) => Record (SummaryFun t) _ -> t r -> r
Enabled by the ScopedTypeVariables
extension, the forall
keyword creates an explicit scope for the type variable t
. Scopes come in different flavors, but when opened in a function's type signature, the scope's extent is the whole body of that function.
I'm not sure this will solve everything for you, but at least you should be getting different errors now.
Building on Fyodor's answer, I have a compiling (but as yet untested) code. I had to change a few assumptions in the type signature, such as returning the result wrapped in Maybe
, and assuming the Traversable
also forms a Semigroup
. I'll revise the wording of the question and this answer once I've had a chance to properly test and construct a self-contained example as suggested by Fyodor:
newtype SummaryFun t a = SummaryFun (t a -> a)
applyRecFun :: forall r t. (Traversable t, Semigroup (t r), _) =>
Record (SummaryFun t) _ -> t r -> Maybe r
applyRecFun func recs =
let recsNP :: t (NP I _) -- a traversable of n-ary products. I is an identity functor
recsNP = toNP . toRecord <$> recs
listrecsNP :: t (NP t _) -- turn every component into a singleton traversable
listrecsNP = liftA_NP (\(I x) -> pure x) <$> recsNP
listrecNPmay :: Maybe (NP t _) -- a single n-ary product where each component is a traversable
listrecNPmay = listrecsNP & (headMay &&& tailMay) & sequenceT
<&> (\(h, t) -> foldr mappend h t)
funcNP :: NP (SummaryFun t) _ -- turn the function record into a n-ary prod
funcNP = toNP func
toRec_NP_I :: NP t _ -> NP I _ -- apply the functions to each list component
toRec_NP_I = liftA2_NP (\(SummaryFun f) vs -> I (f vs)) funcNP
in do
listrecNP <- listrecNPmay
let resultRec_NP_I = toRec_NP_I listrecNP
pure $ fromRecord . fromNP $ resultRec_NP_I -- go back to the nominal record Rec