How to fix type errors, including “Can't quantify over Traversable”, when generifying this SOP function?

后端 未结 2 1017
迷失自我
迷失自我 2021-01-26 06:25

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

相关标签:
2条回答
  • 2021-01-26 07:16

    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.

    0 讨论(0)
  • 2021-01-26 07:19

    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
    
    0 讨论(0)
提交回复
热议问题