Is a scoped type statement possible? - haskell

Is it possible to do the following:
foo = bar
where
type A = (Some, Huge, Type, Sig)
meh :: A -> (A, A) -> A
I only need to use this custom type inside the where clause, so it does not make sense to define it globally.

This isn't possible. Why not just define it above the function? You don't have to export it from the module (just use an explicit export list).
By the way, if you really do have a type that big, it's probably a sign that you should factor it into smaller parts, especially if you have a lot of tuples as your example suggests; data-types would be more appropriate.

Actually, there's one, slightly ridiculous, way to approximate this:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
foo :: forall abbrv. (abbrv ~ (Some, Huge, Type, Sig))
=> abbrv -> abbrv
foo x = meh x (x, x)
where meh :: abbrv -> (abbrv, abbrv) -> abbrv
meh x y = {- ... -}
I can't really recommend enabling two language extensions just for the sake of abbreviating types in signatures, though if you're already using them (or GADTs instead of type families) I suppose it doesn't really hurt anything.
Silliness aside, you should consider refactoring your types in cases like this, as ehird suggests.

Related

How to 'show' unshowable types?

I am using data-reify and graphviz to transform an eDSL into a nice graphical representation, for introspection purposes.
As simple, contrived example, consider:
{-# LANGUAGE GADTs #-}
data Expr a where
Constant :: a -> Expr a
Map :: (other -> a) -> Expr a -> Expr a
Apply :: Expr (other -> a) -> Expr a -> Expr a
instance Functor Expr where
fmap fun val = Map fun val
instance Applicative Expr where
fun_expr <*> data_expr = Apply fun_expr data_expr
pure val = Constant val
-- And then some functions to optimize an Expr AST, evaluate Exprs, etc.
To make introspection nicer, I would like to print the values which are stored inside certain AST nodes of the DSL datatype.
However, in general any a might be stored in Constant, even those that do not implement Show. This is not necessarily a problem since we can constrain the instance of Expr like so:
instance Show a => Show (Expr a) where
...
This is not what I want however: I would still like to be able to print Expr even if a is not Show-able, by printing some placeholder value (such as just its type and a message that it is unprintable) instead.
So we want to do one thing if we have an a implementing Show, and another if a particular a does not.
Furthermore, the DSL also has the constructors Map and Apply which are even more problematic. The constructor is existential in other, and thus we cannot assume anything about other, a or (other -> a). Adding constraints to the type of other to the Map resp. Apply constructors would break the implementation of Functor resp. Applicative which forwards to them.
But here also I'd like to print for the functions:
a unique reference. This is always possible (even though it is not pretty as it requires unsafePerformIO) using System.Mem.StableName.
Its type, if possible (one technique is to use show (typeOf fun), but it requires that fun is Typeable).
Again we reach the issue where we want to do one thing if we have an f implementing Typeable and another if f does not.
How to do this?
Extra disclaimer: The goal here is not to create 'correct' Show instances for types that do not support it. There is no aspiration to be able to Read them later, or that print a != print b implies a != b.
The goal is to print any datastructure in a 'nice for human introspection' way.
The part I am stuck at, is that I want to use one implementation if extra constraints are holding for a resp. (other -> a), but a 'default' one if these do not exist.
Maybe type classes with FlexibleInstances, or maybe type families are needed here? I have not been able to figure it out (and maybe I am on the wrong track all together).
Not all problems have solutions. Not all constraint systems have a satisfying assignment.
So... relax the constraints. Store the data you need to make a sensible introspective function in your data structure, and use functions with type signatures like show, fmap, pure, and (<*>), but not exactly equal to them. If you need IO, use IO in your type signature. In short: free yourself from the expectation that your exceptional needs fit into the standard library.
To deal with things where you may either have an instance or not, store data saying whether you have an instance or not:
data InstanceOrNot c where
Instance :: c => InstanceOrNot c
Not :: InstanceOrNot c
(Perhaps a Constraint-kinded Either-alike, rather than Maybe-alike, would be more appropriate. I suspect as you start coding this you will discover what's needed.) Demand that clients that call notFmap and friends supply these as appropriate.
In the comments, I propose parameterizing your type by the constraints you demand, and giving a Functor instance for the no-constraints version. Here's a short example showing how that might look:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
import Data.Kind
type family All cs a :: Constraint where
All '[] a = ()
All (c:cs) a = (c a, All cs a)
data Lol cs a where
Leaf :: a -> Lol cs a
Fmap :: All cs b => (a -> b) -> Lol cs a -> Lol cs b
instance Functor (Lol '[]) where
fmap f (Leaf a) = Leaf (f a)
fmap f (Fmap g garg) = Fmap (f . g) garg
Great timing! Well-typed recently released a library which allows you to recover runtime information. They specifically have an example of showing arbitrary values. It's on github at https://github.com/well-typed/recover-rtti.
It turns out that this is a problem which has been recognized by multiple people in the past, known as the 'Constrained Monad Problem'. There is an elegant solution, explained in detail in the paper The Constrained-Monad Problem by Neil Sculthorpe and Jan Bracker and George Giorgidze and Andy Gill.
A brief summary of the technique: Monads (and other typeclasses) have a 'normal form'. We can 'lift' primitives (which are constrained any way we wish) into this 'normal form' construction, itself an existential datatype, and then use any of the operations available for the typeclass we have lifted into. These operations themselves are not constrained, and thus we can use all of Haskell's normal typeclass functions.
Finally, to turn this back into the concrete type (which again has all the constraints we are interested in) we 'lower' it, which is an operation that takes for each of the typeclass' operations a function which it will apply at the appropriate time.
This way, constraints from the outside (which are part of the functions supplied to the lowering) and constraints from the inside (which are part of the primitives we lifted) are able to be matched, and finally we end up with one big happy constrained datatype for which we have been able to use any of the normal Functor/Monoid/Monad/etc. operations.
Interestingly, while the intermediate operations are not constrained, to my knowledge it is impossible to write something which 'breaks' them as this would break the categorical laws that the typeclass under consideration should adhere to.
This is available in the constrained-normal Hackage package to use in your own code.
The example I struggled with, could be implemented as follows:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE UndecidableInstances #-}
module Example where
import Data.Dynamic
import Data.Kind
import Data.Typeable
import Control.Monad.ConstrainedNormal
-- | Required to have a simple constraint which we can use as argument to `Expr` / `Expr'`.
-- | This is definitely the part of the example with the roughest edges: I have yet to figure out
-- | how to make Haskell happy with constraints
class (Show a, Typeable a) => Introspectable a where {}
instance (Show a, Typeable a) => Introspectable a where {}
data Expr' (c :: * -> Constraint) a where
C :: a -> Expr' c a
-- M :: (a -> b) -> Expr' a -> Expr' b --^ NOTE: This one is actually never used as ConstrainedNormal will use the 'free' implementation based on A + C.
A :: c a => Expr' c (a -> b) -> Expr' c a -> Expr' c b
instance Introspectable a => Show (Expr' Introspectable a) where
show e = case e of
C x -> "(C " ++ show x ++ ")"
-- M f x = "(M " ++ show val ++ ")"
A fx x -> "(A " ++ show (typeOf fx) ++ " " ++ show x ++ ")"
-- | In user-facing code you'd not want to expose the guts of this construction
-- So let's introduce a 'wrapper type' which is what a user would normally interact with.
type Expr c a = NAF c (Expr' c) a
liftExpr :: c a => Expr' c a -> Expr c a
liftExpr expr = liftNAF expr
lowerExpr :: c a => Expr c a -> Expr' c a
lowerExpr lifted_expr = lowerNAF C A lifted_expr
constant :: Introspectable a => a -> Expr c a
constant val = pure val -- liftExpr (C val)
You could now for instance write
ghci> val = constant 10 :: Expr Introspectable Int
(C 10)
ghci> (+2) <$> val
(C 12)
ghci> (+) <$> constant 10 <*> constant 32 :: Expr Introspectable Int
And by using Data.Constraint.Trivial (part of the trivial-constrained library, although it is also possible to write your own 'empty constrained') one could instead write e.g.
ghci> val = constant 10 :: Expr Unconstrained Int
which will work just as before, but now val cannot be printed.
The one thing I have not yet figured out, is how to properly work with subsets of constraints (i.e. if I have a function that only requires Show, make it work with something that is Introspectable). Currently everything has to work with the 'big' set of constraints.
Another minor drawback is of course that you'll have to annotate the constraint type (e.g. if you do not want constraints, write Unconstrained manually), as GHC will otherwise complain that c0 is not known.
We've reached the goal of having a type which can be optionally be constrained to be printable, with all machinery that does not need printing to work also on all instances of the family of types including those that are not printable, and the types can be used as Monoids, Functors, Applicatives, etc just as you like.
I think it is a beautiful approach, and want to commend Neil Sculthorpe et al. for their work on the paper and the constrained-normal library that makes this possible. It's very cool!

When should TypeApplications be preferred over simple :: signatures or ScopedTypeVariables?

Considering this simple example of ambiguous type inference:
#! /usr/bin/env stack
{- stack runghc -}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
main :: IO ()
main = do
-- This will fail to compile without additional type info
-- let w = read "22"
-- print w
-- My go-to for this is type signatures in the expressions
let x = read "33" :: Integer
print x
-- Another possibility is ScopedtypeVariables
let y :: Integer = read "44"
print y
-- How does TypeApplications differ from the code above? When should this be chosen instead?
let z = read #Integer "55"
print z
My question is, in cases like this, is there an advantage to using TypeApplications?
In almost all cases, it is an aesthetic choice only. I make the following additional comments for your consideration:
In all cases, if a thing typechecks with some collection of type signatures, there is a corresponding collection of type applications that also causes that term to typecheck (and with the same choices of instance dictionaries, etc.).
In cases where either a signature or an application can be used, the code produced by GHC will be identical.
Some ambiguous types cannot be resolved via signatures, and type applications must be used. For example, foo :: (Monoid a, Monoid b) => b cannot be given a type signature that determines a. (This bullet motivates the "almost" in the first sentence of this answer. No other bullet motivates the "almost".)
Type applications are frequently syntactically lighter than type signatures. For example, when the type is long, or a type variable is mentioned several times. Some comparisons:
showsPrec :: Int -> Bool -> String -> String
showsPrec #Bool
sortOn :: Ord b => (Int -> b) -> [Int] -> [Int]
sortOn #Int
Sometimes it is possible to shuffle the type signature around to a different subterm so that you need only give a short signature with little repetition. But then again... sometimes not.
Sometimes, the signature or application is intended to convey some information to the reader or encourage a certain way of thinking about a piece of code (i.e. is not strictly for compiler consumption). If part of that information involves attaching the annotation in a specific code location, your options may be somewhat constrained.

How can I make my type an instance of Arbitrary?

I have the following data and function
data Foo = A | B deriving (Show)
foolist :: Maybe Foo -> [Foo]
foolist Nothing = [A]
foolist (Just x) = [x]
prop_foolist x = (length (foolist x)) == 1
when running quickCheck prop_foolist, ghc tells me that Foo needs to be an instance of Arbitrary.
No instance for (Arbitrary Foo) arising from a use of ‘quickCheck’
In the expression: quickCheck prop_foolist
In an equation for ‘it’: it = quickCheck prop_foolist
I tried data Foo = A | B deriving (Show, Arbitrary), but this results in
Can't make a derived instance of ‘Arbitrary Foo’:
‘Arbitrary’ is not a derivable class
Try enabling DeriveAnyClass
In the data declaration for ‘Foo’
However, I can't figure out how to enble DeriveAnyClass. I just wanted to use quickcheck with my simple function! The possible values of x is Nothing, Just A and Just B. Surely this should be possible to test?
There are two reasonable approaches:
Reuse an existing instance
If there's another instance that looks similar, you can use it. The Gen type is an instance of Functor, Applicative, and even Monad, so you can easily build generators from other ones. This is probably the most important general technique for writing Arbitrary instances. Most complex instances will be built up from one or more simpler ones.
boolToFoo :: Bool -> Foo
boolToFoo False = A
boolToFoo True = B
instance Arbitrary Foo where
arbitrary = boolToFoo <$> arbitrary
In this case, Foo can't be "shrunk" to subparts in any meaningful way, so the default trivial implementation of shrink will work fine. If it were a more interesting type, you could have used some analogue of
shrink = map boolToFoo . shrink . fooToBool
Use the pieces available in Test.QuickCheck.Arbitrary and/or Test.QuickCheck.Gen
In this case, it's pretty easy to just put together the pieces:
import Test.QuickCheck.Arbitrary
data Foo = A | B
deriving (Show,Enum,Bounded)
instance Arbitrary Foo where
arbitrary = arbitraryBoundedEnum
As mentioned, the default shrink implementation would be fine in this case. In the case of a recursive type, you'd likely want to add
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics (Generic)
and then derive Generic for your type and use
instance Arbitrary ... where
...
shrink = genericShrink
As the documentation warns, genericShrink does not respect any internal validity conditions you may wish to impose, so some care may be required in some cases.
You asked about DeriveAnyClass. If you wanted that, you'd add
{-# LANGUAGE DeriveAnyClass #-}
to the top of your file. But you don't want that. You certainly don't want it here, anyway. It only works for classes that have a full complement of defaults based on Generics, typically using the DefaultSignatures extension. In this case, there is no default arbitrary :: Generic a => Gen a line in the Arbitrary class definition, and arbitrary is mandatory. So an instance of Arbitrary produced by DeriveAnyClass will produce a runtime error as soon as QuickCheck tries to call its arbitrary method.

Creating custom data types with constraints

I'm trying to create a custom data type. As an example
data Time = Second Int deriving (Show)
However, this is too limiting (we could say later need milliseconds). I would like to instead define something like this:
data Time = Second Num deriving (Show)
This doesn't compile because Num has kind * -> ghc-prim-0.4.0.0:GHC.Prim.Constraint
How do I setup Time such that Second may contain any Num?
One of the best examples of why this might not be so desirable is found here at the Wikibooks section on Classes and Types. They say:
Type constraints in data declarations are less useful than it might seem at first. Consider:
data (Num a) => Foo a = F1 a | F2 a String
Here, Foo is a type with two constructors, both taking an argument of a type a which must be in Num. However, the (Num a) => constraint is only effective for the F1 and F2 constructors, and not for other functions involving Foo. Therefore, in the following example...
fooSquared :: (Num a) => Foo a -> Foo a
fooSquared (F1 x) = F1 (x * x)
fooSquared (F2 x s) = F2 (x * x) s
... even though the constructors ensure a will be some type in Num we can't avoid duplicating the constraint in the signature of fooSquared
This suggests that a reasonable option for you is to just create Time with a generic parameter, and then later ensure that the module functions that operate on Time data always have the necessary constraint for Num.
It won't be so much of a worry that someone goes off and foolishly makes Time String or something -- if they do, then none of the provided module functions are going to be helpful for them, so it doesn't matter so much.
There are also options to look up with GADTs, the {-# LANGUAGE GeneralizedNewtypeDeriving #-} pragma, and the {-# LANGUAGE DatatypeContexts #-} pragma. But usually these start to rope in unnecessary degrees of extra complexity, especially if you're a Haskell novice like me.
There is a deprecated feature called Datatype Contexts that allows you to do that:
{-# LANGUAGE DatatypeContexts #-}
data Num a => Time a = Second a deriving (Show)
t = Second (5 :: Int)
main = print t
This executes on GHC 7.8.3 (sorry, don't have 7.10 to check), but warns you about the deprecation:
t.hs:1:14: Warning:
-XDatatypeContexts is deprecated: It was widely considered a
misfeature, and has been removed from the Haskell language.
Second 5
A non-deprecated way to do it is to use Generalized Algebraic Datatypes (GADTs) (and you'll need standalone deriving as well):
{-# LANGUAGE GADTs, StandaloneDeriving #-}
data Time a where
Second :: Num a => a -> Time a
deriving instance Show a => Show (Time a)
t = Second (5 :: Int)
main = print t
If you try to create a variable with something non-Num, you'll get a compilation error:
t = Second "a"
t.hs:12:5:
No instance for (Num [Char]) arising from a use of ‘Second’
In the expression: Second "a"
In an equation for ‘t’: t = Second "a"

Is it possible to export constructors for pattern matching, but not for construction, in Haskell Modules?

A vanilla data type in Haskell has zero or more constructors, each of which plays two roles.
In expressions, it supports introduction, its a function from zero or more arguments to the data type.
In patterns, it supports elimination, its kinda like a function from the data type to Maybe (tuple of argument types).
Is it possible for a module signature to hide the former while exposing the latter?
The use case is this: I have a type, T, whose constructors types alone can sometimes be used to construct nonsense. I have construction functions which can be used to build instances of the type that are guaranteed not to be nonsense. It would make sense to hide the constructors in this case, but it would still be useful for callers to be able to pattern match over the guaranteed-non-nonsense that they build with the construction functions.
I suspect this is impossible, but in case anyone has a way to do it, I though I would ask.
Next best thing is to hide the constructors and create a bunch of functions from T -> Maybe (This, That), T -> Maybe (The, Other, Thing), etc.
You can use a view type and view patterns to do what you want:
module ThingModule (Thing, ThingView(..), view) where
data Thing = Foo Thing | Bar Int
data ThingView = FooV Thing | BarV Int
view :: Thing -> ThingView
view (Foo x) = FooV x
view (Bar y) = BarV y
Note that ThingView is not a recursive data type: all the value constructors refer back to Thing. So now you can export the value constructors of ThingView and keep Thing abstract.
Use like this:
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> FooV x) = doSomethingWithThing x
doSomethingWithThing(view -> BarV y) = y
The arrow notation stuff is GHC's View Patterns. Note that it requires a language pragma.
Of course you're not required to use view patterns, you can just do all the desugaring by hand:
doSomethingWithThing :: Thing -> Int
doSomethingWithThing = doIt . view
where doIt (FooV x) = doSomethingWithThing x
doIt (BarV y) = y
More
Actually we can do a little bit better: There is no reason to duplicate all the value constructors for both Thing and ThingView
module ThingModule (ThingView(..), Thing, view) where
newtype Thing = T {view :: ThingView Thing}
data ThingView a = Foo a | Bar Int
Continue useing it the same way as before, but now the pattern matches can use Foo and Bar.
{-# LANGUAGE ViewPatterns #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing(view -> Foo x) = doSomethingWithThing x
doSomethingWithThing(view -> Bar y) = y
From GHC 7.8 on you can use PatternSynonyms to export patterns independent from constructors. So an analogue to #Lambdageek’s answer would be
{-# LANGUAGE PatternSynonyms #-}
module ThingModule (Thing, pattern Foo, pattern Bar) where
pattern Foo a <- RealFoo a
pattern Bar a <- RealBar a
data Thing = RealFoo Thing | RealBar Int
and
{-# LANGUAGE PatternSynonyms #-}
module Main where
import ThingModule
doSomethingWithThing :: Thing -> Int
doSomethingWithThing (Foo x) = doSomethingWithThing x
doSomethingWithThing (Bar y) = y
So it looks like normal constructors.
If you try to use Bar to construct a value, you get
Main.hs:9:32:
Bar used in an expression, but it's a non-bidirectional pattern synonym
In the expression: Bar y
You cannot. But if there are only reasonable number of constructors for your type T, you may want to hide the constructors and instead provide a function which does the pattern matching in the same spirit as maybe :: b -> (a -> b) -> Maybe a -> b.

Resources