I'm trying to conjure a traversal to update multiple keys of an IntMap as a whole.
To dispell XY: I'm not simply trying to update them, I need the traversal to return to the caller for further composition. Or at least something composable with lenses.
I've tried many variations of the common combinators. I've tried dropping down to a functor-based definition, with a large range of experimentation shifting the foralls' scopes around, with no more success. Building from the ground up again, here's where I'm at:
import Control.Lens
import Control.Lens.Unsound
-- base case: traverse a single fixed element
t1 :: Traversal' (IntMap a) (Maybe a)
t1 = at 0
-- build-up case: traverse a pair of fixed elements
t2 :: Traversal' (IntMap a) (Maybe a)
t2 = at 0 `adjoin` at 1
-- generalizing case: do it with a fold
t3 :: Traversal' (IntMap a) (Maybe a)
t3 = foldr (\e t -> at e `adjoin` t) (at 1) [0]
t1 and t2 work fine; I'd devised t3 to be equivalent to t2, but it fails with the following error:
• Couldn't match type ‘f1’ with ‘f’
‘f1’ is a rigid type variable bound by a type expected by the context:
Traversal' (IntMap a) (Maybe a)
‘f’ is a rigid type variable bound by the type signature for:
t3 :: forall a. Traversal' (IntMap a) (Maybe a)
Expected type: (Maybe a -> f1 (Maybe a)) -> IntMap a -> f1 (IntMap a)
Actual type: (Maybe a -> f (Maybe a)) -> IntMap a -> f (IntMap a)
• In the second argument of ‘adjoin’, namely ‘t’
In the expression: at x `adjoin` t
In the first argument of ‘foldr’, namely ‘(\ x t -> at x `adjoin` t)’
I suppose this is some rank-2 trickery that's still a bit over my head. Is there any way to make this work?
I aimed for a final signature of
ats :: Foldable l => l Int -> Traversal' (IntMap a) (Maybe a)
…assuming unique keys, of course. Which I dreamed could be implemented just almost like t3.
Traversal' is a type synonym for a type containing forall, which makes it a second class citizen in the type system: we can't instantiate a type variable with such a type.
In particular, here we are trying to do so with foldr :: (a -> b -> b) -> b -> [a] -> b, we can't instantiate b = Traversal' _ _, because Traversal' contains a forall.
One work around is to wrap Traversal' in a newtype, ReifiedTraversal. Wrap (using the Traversal constructor) before passing at 1 to foldr; inside foldr, unwrap to use adjoin, and rewrap; unwrap at the end.
t3 :: Traversal' (IntMap a) (Maybe a)
t3 = runTraversal (foldr (\e t -> Traversal (at e `adjoin` runTraversal t)) (Traversal (at 1)) [0])
A traversal is a function Applicative f => (t -> f t) -> (s -> f s). You have a function f :: Maybe a -> f (Maybe a) and you want to apply it to some entries in IntMap a.
It's a bit of a puzzle to do with Applicative (there is a more natural solution using Monad), but requires less expertise than composing traversals as first-class values:
import Control.Applicative
import Data.IntMap (IntMap)
import qualified Data.IntMap as M
-- [Int] -> Traversal' (IntMap a) (Maybe a)
traverseAtKeys :: Applicative f => [Int] -> (Maybe a -> f (Maybe a)) -> IntMap a -> f (IntMap a)
traverseAtKeys keys f m =
let go i k = liftA2 (insertMaybe i) (f (M.lookup i m)) k
insertMaybe i Nothing = M.delete i
insertMaybe i (Just v) = M.insert i v
in foldr go (pure m) keys
One way to get around problems like this is to use a newtype wrapper. Specifically, consider the following:
newtype TravJoiner a b = TravJoiner { unTravJoiner :: Traversal' a b }
instance Semigroup (TravJoiner a b) where
TravJoiner x <> TravJoiner y = TravJoiner $ adjoin x y
With this, you can write your t3 without any trouble:
t3 :: Traversal' (IntMap a) (Maybe a)
t3 = unTravJoiner $ foldr (\e t -> TravJoiner (at e) <> t) (TravJoiner $ at 1) [0]
Your ats function follows nicely from there:
ats :: Foldable l => l Int -> Traversal' (IntMap a) (Maybe a)
ats = unTravJoiner . foldr (\e t -> TravJoiner (at e) <> t) (TravJoiner ignored)
Related
I'm trying to learn monads better and am playing around with it in Haskell. I defined a monad in this way:
module TESTMonad where
import Control.Monad
newtype TEST i = TEST {getTEST :: ((i, Int), Int)} deriving (Show, Eq, Ord)
instance Functor TEST where
fmap f (TEST ((x,y), z)) = TEST ((f x, y), z)
instance Applicative TEST where
pure = return
tf <*> tx = tf >>= \f -> tx >>= \x -> return (f x)
instance Monad TEST where
return x = TEST ((x, 1), 1)
(TEST ((x, y), z)) >>= f = TEST ((plusOne a, b), c)
where
((a, b), c) = getTEST (f x)
plusOne :: Int -> Int
plusOne x = x+1
but I get the following error when I'm trying to compile it:
TESTMonad.hs:16:47: error:
• Couldn't match expected type ‘Int’ with actual type ‘b’
‘b’ is a rigid type variable bound by
the type signature for:
(>>=) :: forall a b. TEST a -> (a -> TEST b) -> TEST b
at TESTMonad.hs:16:24
• In the first argument of ‘plusOne’, namely ‘a’
In the expression: plusOne a
In the expression: (plusOne a, b)
• Relevant bindings include
a :: b (bound at TESTMonad.hs:18:19)
f :: a -> TEST b (bound at TESTMonad.hs:16:28)
(>>=) :: TEST a -> (a -> TEST b) -> TEST b
(bound at TESTMonad.hs:16:5)
Failed, modules loaded: none.
I clearly know that I might be doing lots of things in the wrong way but I have no idea what are they. Any comment would be appreciated. Thank you in advance!
The Monad instance cannot be constrained. The type of (>>=) must be
Monad m => m a -> (a -> m b) -> m b
but your definition, using plusOne :: Int -> Int, makes the type
Monad m => m Int -> (Int -> m Int) -> m Int
You could safely apply plusOne to either of the other values wrapped inside TEST, as they are already defined to be Ints.
The definition of (>>=) has no idea what the type of x might be, and the caller gets to choose f, so it has no idea what the type of f x might either. As a result, you can't really do anything with it except use it as-is.
In general, I'm wondering if there's a way to write a generic fold that generalizes a function that applies a forall type like:
f :: forall a. Data (D a) => D a -> b
given some datatype D for which instance Data (D a) (possibly with constraints on a). To be concrete, consider something even as simple as False `mkQ` isJust, or generally, a query on the constructor of a higher-kinded datatype. Similarly, consider a transformation mkT (const Nothing) that only affects one particular higher-kinded type.
Without explicit type signatures, they fail with No instance for Typeable a0, which is probably the monomorphism restriction at work. Fair enough. However, if we add explicit type signatures:
t :: GenericT
t = mkT (const Nothing :: forall a. Data a => Maybe a -> Maybe a)
q :: GenericQ Bool
q = False `mkQ` (isJust :: forall a. Data a => Maybe a -> Bool)
instead we are told that the forall type of the outer signatures are ambiguous:
Could not deduce (Typeable a0)
arising from a use of ‘mkT’
from the context: Data a
bound by the type signature for:
t :: GenericT
The type variable ‘a0’ is ambiguous
I can't wrap my head around this. If I'm really understanding correctly that a0 is the variable in t :: forall a0. Data a0 => a0 -> a0, how is it any more ambiguous than in say mkT not? If anything, I would've expected mkT to complain because it is the one that interacts with isJust. Additionally, these functions are more polymorphic than the branching on concrete types.
I'm curious to know if this is a limitation of proving the inner constraint isJust :: Data a => ... — my understanding is that any type of instance Data inhabited with Maybe a must also have Data a to be valid by the instance constraint instance Data a => Data (Maybe a).
tldr: You need to create a different function.
mkT has the following signature:
mkT :: (Typeable a, Typeable b) => (a -> a) -> (b -> b)
And you want to apply it to a polymorphic function of type (forall x. Maybe x -> Maybe x). It is not possible: there is no way to instantiate a in (a -> a) to obtain (forall x. Maybe x -> Maybe x).
It's not just a limitation of the type system, the implementation of mkT wouldn't support such an instantiation either.
mkT simply compares concrete types a and b for equality at run time. But what you want is to be able to test whether b is equal to Maybe x for some x. The logic this requires is fundamentally more involved. But it is certainly still possible.
Below, mkT1 first matches the type b against the App pattern to know whether b is some type application g y, and then tests equality of g and f:
{-# LANGUAGE ScopedTypeVariables, RankNTypes, TypeApplications, GADTs #-}
import Type.Reflection
-- N.B.: You can add constraints on (f x), but you must do the same for b.
mkT1 :: forall f b. (Typeable f, Typeable b) => (forall x. f x -> f x) -> (b -> b)
mkT1 h =
case typeRep #b of
App g y ->
case eqTypeRep g (typeRep #f) of
Just HRefl -> h
_ -> id
_ -> id
Compilable example with mkQ1 as well:
{-# LANGUAGE ScopedTypeVariables, RankNTypes, TypeApplications, GADTs #-}
import Type.Reflection
mkT1 :: forall f b. (Typeable f, Typeable b) => (forall x. f x -> f x) -> (b -> b)
mkT1 h =
case typeRep #b of
App g y ->
case eqTypeRep g (typeRep #f) of
Just HRefl -> h
_ -> id
_ -> id
mkQ1 :: forall f b q. (Typeable f, Typeable b) => (forall x. f x -> q) -> (b -> q) -> (b -> q)
mkQ1 h =
case typeRep #b of
App g y ->
case eqTypeRep g (typeRep #f) of
Just HRefl -> const h
_ -> id
_ -> id
f :: Maybe x -> String
f _ = "matches"
main :: IO ()
main = do
print (mkQ1 f (\_ -> "doesn't match") (Just 3 :: Maybe Int)) -- matches
print (mkQ1 f (\_ -> "doesn't match") (3 :: Int)) -- doesn't match
I can define a polykinded natural transformation like so:
type family (~>) :: k -> k -> *
type instance (~>) = (->)
newtype NT a b = NT { apply :: forall x. a x ~> b x }
type instance (~>) = NT
Which works at all kinds, so I can define e.g.
left :: Either ~> (,)
left = NT (NT (Left . fst))
This is cool and inspiring. But no matter how many tricks I play, I can't seem to get something variadic in the return type. E.g. I would like
type family (:*:) :: k -> k -> k
type instance (:*:) = (,)
type instance (:*:) = ???
It seems like this is impossible, since type families need to be fully saturated, and you can only introduce type constructors in *.
I've even tried some rather nasty tricks
type instance (:*:) = Promote2 (:*:)
type family Promote2 :: (j -> k -> l) -> (a -> j) -> (a -> k) -> (a -> l) where
promote2_law :: Promote2 f x y z :~: f (x z) (y z)
promote2_law = unsafeCoerce Refl
fstP :: forall (a :: k -> *) (b :: k -> *) (c :: k). (a :*: b) c -> a c
fstP = case promote2_law #(:~:) #a #b #c of Refl -> NT (\(a,b) -> a)
And I don't know if that even has any hope of working, since I haven't thought through how higher kinded things are "represented". But GHC knows I'm lying anyway
• Couldn't match type ‘(,)’ with ‘Promote2 (,) a’
Inaccessible code in
a pattern with constructor: Refl :: forall k (a :: k). a :~: a,
Are there any other tricks for this?
The "axiomatic" approach does actually work, I had just used the equality wrong:
fstP :: forall (a :: j -> k) (b :: j -> k) (x :: j). (a :*: b) x -> a x
fstP = castWith (Refl ~% promote2_law #(:*:) #a #b #x ~% Refl) fst
where
infixl 9 ~%
(~%) = Data.Type.Equality.apply
Using Equality.apply is essential to inform the type checker of where to apply the axiom. I made a full development of higher-kinded products here for reference.
Be warned, as I was playing with this did I get a GHC panic once. So the nasty tricks might be nasty. Still interested in other approaches.
data T t where
A :: Show (t a) => t a -> T t
B :: Coercible Int (t a) => t a -> T t
f :: T t -> String
f (A t) = show t
g :: T t -> Int
g (B t) = coerce t
Why does f compile but g generate an error like follows? I'm using GHC 8.4.
• Couldn't match representation of type ‘Int’ with that of ‘t a’
Inaccessible code in
a pattern with constructor:
B :: forall k (t :: k -> *) (a :: k).
Coercible Int (t a) =>
t a -> T t,
in an equation for ‘g’
• In the pattern: B t
In an equation for ‘g’: g (B t) = coerce t
Also, are Coercible constraints zero-cost even when they are embedded in GADTs?
UPD: Compiler bug: https://ghc.haskell.org/trac/ghc/ticket/15431
As a workaround, you may replace the constraint (which is not free in the first place) with a Data.Type.Coercion.Coercion (which adds an extra data wrapper around the dictionary).
data T t where
A :: Show (t a) => t a -> T t
B :: !(Coercion Int (t a)) -> t a -> T t
-- ! for correctness: you can’t have wishy-washy values like B _|_ (I "a")
-- Such values decay to _|_
f :: T t -> String
f (A x) = show x
f (B c x) = show (coerceWith (sym c) x)
newtype I a = I a
main = putStrLn $ f $ B Coercion $ I (5 :: Int)
GHC 8.6 will improve this situation in two ways:
Your original code will work, as the underlying bug was fixed.
The Coercion can be unpacked to a Coercible constraint, and this will happen automatically, due to -funbox-small-strict-fields. Thus, this T will get performance characteristics equivalent to your original for free.
In the first hunk, filterF is implemented with foldMap
import Data.List
pred :: a -> Bool
pred = undefined
wrapperOfA :: (Applicative f, Monoid (f a)) => a -> Bool -> f a
wrapperOfA a condition = if condition then pure a else mempty
-- foldMap :: (Foldable t, Monoid f a) => (a -> f a) -> t a -> f a
filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a
filterF pred = foldMap ((<*>) wrapperOfA pred)
filterF (<3) [5,4,3,2,1] :: [Int]
-- [2,1]
... which utilises some Applicative's apply function, aka <*> typically infixed. Now, the type of <*> is:
:t (<*>)
--(<*>) :: forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
But replacing it with a hole gives its type as
-- (a0 -> Bool -> f0 a0) -> (a -> Bool) -> a -> f a
-- namely, from typechecking
filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a
filterF pred = foldMap (_ wrapperOfA pred)
-- Found hole ‘_’ with type: (a0 -> Bool -> f0 a0) -> (a -> Bool) -> a -> f a
-- Where: ‘a’ is a rigid type variable bound by the type signature for interactive:IHaskell136.filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a at :1:12
-- ‘f’ is a rigid type variable bound by the type signature for interactive:IHaskell136.filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a at :1:12
-- ‘a0’ is an ambiguous type variable
-- ‘f0’ is an ambiguous type variable
-- Relevant bindings include
-- pred :: a -> Bool (bound at :2:9)
-- filterF :: (a -> Bool) -> t a -> f a (bound at :2:1)
-- In the expression: _
-- In the first argument of ‘foldMap’, namely ‘(_ wrapperOfA pred)’
-- In the expression: foldMap (_ wrapperOfA pred)
Basically, wrapperOfA does not look like f (a -> b) as <*> would imply, nor does pred look like type f a. Yet it works and type checks - why?
The (<*>) there uses the Applicative instance for functions. In...
-- Writing it infix, for the sake of clarity.
filterF pred = foldMap (wrapperOfA <*> pred)
... wrapperOfA has type a -> (Bool -> f a), and pred has type a -> Bool. That being so, wrapperOfA <*> pred has type a -> f a, as expected. If we substitute the implementation of (<*>) for functions (see the question linked to above for details), we get...
filterF pred = foldMap (\a -> wrapperOfA a (pred a))
... which makes it clear what is going on.
<*> uses the Applicative instance for functions
(<*>) :: f (a -> b) -> f a -> f b
where f is a (->) r , namely a function from the r domain.
Substituting, the first argument of <*> becomes a function from the r domain AND the a domain, then returning a b (a function of 2 arguments, since type r -> (a -> b) is equivalent to r -> a -> b), and the second argument becomes a function from the r domain returning an a.
To produce a (->) r b, we should apply the second-argument (a function) to the r parameter, and the resulting a is passed as a second argument to the thing in front of <*>. That is,
(<*>) wrapperOfA pred r = wrapperOfA r (pred r)
This leads me to a follow-up question/comment to bring the focus to foldMap and filterF which I now rename filterH.
filterH :: (a -> Bool) -> t a -> h a
foldMap :: (a -> f a) -> t a -> f a
wrapperOfA <*> pred :: a -> h a
where h is any applicative and monoid with corresponding pure and mempty but is as yet undefined. So I needed to request a return type eg ::[Int] in order for it to compile&evaluate. Can filterH be used without having to specify my own type h? Am I missing something in this solution?
This is a question from the textbook "haskell programming from first principles", in the foldables section.
Maybe you'll find easier this solution:
import Control.Conditional (select)
filterF :: (Applicative f, Foldable t, Monoid (f a)) => (a -> Bool) -> t a -> f a
filterF f = foldMap (select f pure mempty)
Here, select is just a functional if-then-else, where you provide functions for the condition, the true case and the else case.