简体   繁体   中英

Why does `let foo = (fmap . const)` fail with “No instance for (Functor f0) arising from a use of `fmap'”?

In ghci I can do this:

ghci> (fmap . const) 5 [1,2,3,4,5]
[5,5,5,5,5]

but if I try to extract the sub-expression (fmap . const) into a variable I get an error:

ghci> let foo = (fmap . const)

<interactive>:3:12:
    No instance for (Functor f0) arising from a use of `fmap'
    The type variable `f0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Functor ((,) a) -- Defined in `GHC.Base'
      instance Functor ((->) r) -- Defined in `GHC.Base'
      instance Functor IO -- Defined in `GHC.Base'
      ...plus two others
    In the first argument of `(.)', namely `fmap'
    In the expression: (fmap . const)
    In an equation for `foo': foo = (fmap . const)

I thought this might mean GHC's type inference was failing somehow, but when I ask ghci for the type of the subexpresiion in isolation it has no problem:

ghci> :t (fmap . const)
(fmap . const) :: Functor f => b -> f a -> f b

So what's going on here? Is there any way to extract this subexpression into a variable? Why doesn't the straightforward let work?

Update:

"What is the monomorphism restriction" might be a good thing to link to in an answer (ie: "See also..."), but this isn't a duplicate of that question unless StackOverflow has become some sort of weird version of the game show Jeopardy. I already knew of the monomorphism restriction when I asked this question, but it was not at all obvious to me that MR was the cause of the error I was receiving.

The answer to that question doesn't help in that regard. It says "What this means is that, in some circumstances, if your type is ambiguous ... the compiler will choose to instantiate that type to something not ambiguous", which almost the opposite of what is happening here (MR is creating ambiguity, not removing it.)

It's the dreaded monomorphism restriction. If you run :set -XNoMonomorphismRestriction it will work. You can also define it with an explicit type signature like this

foo :: Functor f => b -> f a -> f b
foo = fmap . const

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