简体   繁体   中英

Why is a monoidal constraint implied by this function, even though only SemiGroup is listed as a constraint?

In the following stack script, I can't apply my strangeHeadMay function to a NonEmpty list, but it works fine on a regular list.

#!/usr/bin/env stack
{- stack script --nix --resolver lts-13.6 -}

{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-} -- hide some scary types

import           Control.Arrow                    ((&&&))
import           Control.Monad                    (join)
import           Data.Foldable                    (toList)
import           Data.Function                    ((&))
import           Data.Functor                     ((<&>))
import           Data.List.NonEmpty               (NonEmpty(..))
import qualified Data.List.NonEmpty               as LNE
import           Data.Maybe                       (catMaybes)
import           Data.Tuple.Sequence              (sequenceT)


strangeHeadMay :: forall a t. (Semigroup (t a), _) => t a -> Maybe a
strangeHeadMay xs =
  let xsWrapped :: t (t a) = pure <$> xs -- <- Contrived example
      -- This is the functionality I actually need:
      xsMay :: Maybe (t a) = xsWrapped & (headMay &&& tailMay) & sequenceT
         <&> (\(h, t) -> foldr mappend h t)
   in do
    xs' <- xsMay
    xs' & toList & headMay

main :: IO ()
main = do
  let nexs :: NonEmpty (Maybe Double) = Nothing :| [Just (2.0)]
  let xs = LNE.toList nexs
  let xsHead = strangeHeadMay xs
  let nexsHead = strangeHeadMay nexs
  pure ()


headMay :: Foldable f => f a -> Maybe a
headMay = foldr (const . Just) Nothing

tailMay :: Foldable f => f a -> Maybe (f a)
tailMay = foldr (seq . Just) Nothing

The error is

/home/brandon/workspace/foldNEmaybes.hs:34:18: error:
    • No instance for (Monoid (NonEmpty (Maybe Double)))
        arising from a use of ‘strangeHeadMay’
    • In the expression: strangeHeadMay nexs
      In an equation for ‘nexsHead’: nexsHead = strangeHeadMay nexs
      In the expression:
        do let nexs :: NonEmpty (Maybe Double) = Nothing :| ...
           let xs = LNE.toList nexs
           let xsHead = strangeHeadMay xs
           let nexsHead = strangeHeadMay nexs
           ....
   |
34 |   let nexsHead = strangeHeadMay nexs
   |                  ^^^^^^^^^^^^^^^^^^^

Also, I must admit I'm not totally clear on why I need the partially typed signature, but changing (Semigroup (ta), _) to (Semigroup (ta)) makes bad things happen.

Even though <> and mappend do the same thing, you can only use the latter if you have a Monoid constraint, so one got added to your _ in the type signature. To fix it, use foldr (<>) instead of foldr mappend .

And you don't need the hole in the type signature. You can write out what goes in it and it'll still work: Applicative t and Foldable t .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM