Consider the following code snippet:
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Vector.Unboxed as UV
import qualified Data.Vector.Generic as V
bar :: Int -> UV.Vector Char -> (Text, Text)
bar i v = (t_pre, t_post)
where
f = T.pack . V.toList
(t_pre, t_post) = (\(x, y) -> (f x, f y)) $ V.splitAt i v
This compiles ok as you might expect. However, if you replace the function calls with view patterns, you get a type error.
{-# LANGUAGE ViewPatterns #-}
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Vector.Unboxed as UV
import qualified Data.Vector.Generic as V
bar :: Int -> UV.Vector Char -> (Text, Text)
bar i v = (t_pre, t_post)
where
f = T.pack . V.toList
(f -> t_pre, f -> t_post) = V.splitAt i v
This prints the following message (with -fprint-potential-instances
):
• Ambiguous type variable ‘v0’ arising from a use of ‘V.toList’
prevents the constraint ‘(V.Vector v0 Char)’ from being solved.
Relevant bindings include
f :: v0 Char -> Text (bound at Weird.hs:11:5)
Probable fix: use a type annotation to specify what ‘v0’ should be.
These potential instances exist:
instance V.Vector UV.Vector Char
-- Defined in ‘Data.Vector.Unboxed.Base’
...plus one instance involving out-of-scope types
instance primitive-0.6.3.0:Data.Primitive.Types.Prim a =>
V.Vector Data.Vector.Primitive.Vector a
-- Defined in ‘Data.Vector.Primitive’
• In the second argument of ‘(.)’, namely ‘V.toList’
In the expression: T.pack . V.toList
In an equation for ‘f’: f = T.pack . V.toList
|
11 | f = T.pack . V.toList
| ^^^^^^^^
Weird.hs:13:6: error:
Variable not in scope: f :: UV.Vector Char -> t
|
13 | (f -> t_pre, f -> t_post) = V.splitAt i v
| ^
Weird.hs:13:18: error:
Variable not in scope: f :: UV.Vector Char -> t1
|
13 | (f -> t_pre, f -> t_post) = V.splitAt i v
| ^
My understanding is that both the ways of expressing things are entirely equivalent, because a view pattern is just function application without naming the bound variable. Am I misunderstanding view patterns? Is it the desugaring that is interacting with the type checker in an unexpected manner? If I inline the definition of f
at both the call sites, the type error goes away.
I've tested this with GHCi 8.4.3.
Update: This is a compiler bug. See GHC Trac #14293 for more details.
You have a problem with f
which is caused by the monomorphism restriction. If you eta expand f
, give it a type signature, or turn on NoMonomorphismRestriction
, then this error will go away.
But you're still left with these errors, which came as a surprise to me!
Weird.hs:13:6: error:
Variable not in scope: f :: UV.Vector Char -> t
|
13 | (f -> t_pre, f -> t_post) = V.splitAt i v
| ^
Weird.hs:13:18: error:
Variable not in scope: f :: UV.Vector Char -> t1
|
13 | (f -> t_pre, f -> t_post) = V.splitAt i v
| ^
I guess view patterns don't work if they are defined in the same scope. To see if view patterns needed to be top-level, I tried
bar :: Int -> UV.Vector Char -> (Text, Text)
bar i v = let (f -> t_pre, f -> t_post) = V.splitAt i v in (t_pre, t_post)
where
f = T.pack . V.toList
which worked fine. So I tried
f = T.pack . V.toList
(f -> t_pre, f -> t_post) = V.splitAt 0 UV.empty
Which fails with f
not in scope.
Finally, if I put those patterns under a function call
f = T.pack . V.toList
g (f -> t_pre, f -> t_post) = V.splitAt 0 UV.empty
then it's fine again. So I guess the rule is that a "value" pattern binding can't use a view pattern which is defined in the same scope. I find that weird, it might even be a bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With