Why are all recursive pattern synonyms rejected? - haskell

{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
data Quun = Foo | Bar | Oink Quun
fooey :: Quun -> Bool
fooey Foo = True
fooey (Oink Yum) = True
fooey _ = False
pattern Yum <- (fooey -> True)
This doesn't compile (at least in GHC-7.10.2)
/tmp/wtmpf-file10227.hs:1:1:
Recursive pattern synonym definition with following bindings:
foo (defined at /tmp/wtmpf-file10227.hs:(6,1)-(8,13))
Yum (defined at /tmp/wtmpf-file10227.hs:10:1-28)
Sure, for simple directly self-referring patterns this would make sense. But is there some fundamental reason why even a view-pattern mediated layout as above isn't possible? I can't find this convincing; after all it's possible to inline the view pattern and get a perfectly harmless (well... at least, allowed) definition:
fooey :: Quun -> Bool
fooey Foo = True
fooey (Oink (fooey -> True)) = True
fooey _ = False
pattern Yum <- (fooey -> True)
So, are such synonyms just not available yet for technical reasons, and will we get them in the future?

Some recursive patterns are problematic, like
f :: [()] -> Bool
f L = True
f _ = False
pattern L <- () : L
What is this supposed to desugar to?
Patterns aren't first-class values. They are just replaced with their definitions where they appear. For such a language, recursive definitions are not generally sensible.

Related

Pattern synonym with "virtual" arg and conjunction

Let's say I have types:
data Some a = S1 a | S2 a
data BigRec = BigRec {
some :: Some [Int]
, ...
}
and I want a pattern synonym that will have a "virtual argument", like
pattern BadBigRec t <- ...
where t is True or False which depends on the value of some: if it's S1 something-particular - it's True, else if it is S2 something-other, it's False. I hit 2 problems: I don't know how to have an "argument" in a pattern synonym which is only in the left hand side and it is not presented in the right hand side (t is "virtual" and it does not exist in BigRec or Some). And the second problem, I don't know how to express "OR" (conjunction) in pattern synonyms. Not just pattern that match, but a conjunct of predicates.
Is it possible with pattern synonyms or only pattern views are useful for such cases?
As mentioned in the comments, you can use a view pattern.
{-# LANGUAGE ViewPatterns, PatternSynonyms #-}
data Some a = S1 a | S2 a
data BigRec = BigRec {
some :: Some [Int]
}
pattern BadBigRec :: Bool -> BigRec
pattern BadBigRec t <- (checkBad -> t)
-- modify this as needed
checkBad :: BigRec -> Bool
checkBad x = case some x of
S1 _ -> True
S2 _ -> False

List of any `DataKind` in GADT

Disclaimer
GADTs & DataKinds are unexplored territory for me, so some of the limitations and capabilities of them are unknown to me.
The Question
So I'm writing an AST for a JavaScript code emitter, and I've identified one edge case between expressions and that is that they can either be a reference or not. So I've used GADTS and datakinds to type this aspect of JavaScript expression semantics. The ast looks something like this.
Subset of the expression AST
-- at the moment I'm just using a bool to identify if the expression
-- behaves as an reference, but I'll probably change it due to the fact
-- a bool is pretty vague
data JSExp :: Bool -> * where
JSNumber :: Double -> JSExp False
JSBool :: Bool -> JSExp False
JSReference :: Text -> JSExp True
JSProperty :: JSExp a -> Text -> JSExp True
JSAssign :: JSExp True -> JSExp b -> JSExp b
This looks all fine and dandy, because an assignment expression requires the first expression to be a reference like a property expression ("test".shadyProperty) or a reference/identifier.
The problem
Now I want to add an array literal expression, in JavaScript it shouldn't matter what is in this list so lists like this are legal
[a, 1, true, a.b]
In my AST however this is not legal because there are multiple types in the list
data JSExp :: Bool -> * where
-- ...
JSArray :: [JSExp ???] -> JSExp False
let aref = JSReference "a"
in JSArray [aref, JSNumber 2, JSBool True, JSProp aref "b"]
What goes in the place of ??? for the type? A similar problem occurs when I want to build out a constructor for JSObject's and JSFunctionCall's, as these are also expressions.
Idris's soultion
In Idris ??? would look something like this.
data JSExp : Bool -> Type where
JSArray : List (JSExp _) -> JSExp False
JSNumber : Float -> JSExp False
JSBool : Bool -> JSExp False
-- ...
Potenial soultions
Wrapping type
One soultion that isn't like the Idris one, would to have a wrapper type like this
data JSExpWrap = Refs (JSExp True) | NoRef (JSExp False)
This would make the api of my library gross and it's not what I'm looking for.
In Summary
I'm looking for the equivalent that's found in Idris, and an explanation of the implications of the solution. If there's no equivalent, a solution of the next best thing is what I'm looking for.
You can use existentials:
{-# LANGUAGE GADTs, DataKinds, PolyKinds #-}
data Exists :: (k -> *) -> * where
This :: p x -> Exists p
data JSExp :: Bool -> * where
...
JSArray :: [Exists JSExp] -> JSExp False
test = let aref = JSReference "a"
in JSArray [This aref, This (JSNumber 2), This (JSBool True), This (JSProperty aref "b")]
Or with some sugar:
infixr 5 !:
(!:) :: p x -> [Exists p] -> [Exists p]
x !: xs = This x : xs
test = let aref = JSReference "a"
in JSArray $ aref !: JSNumber 2 !: JSBool True !: JSProperty aref "b" !: []

Test if a value matches a constructor

Say I have a data type like so:
data NumCol = Empty |
Single Int |
Pair Int Int |
Lots [Int]
Now I wish to filter out the elements matching a given constructor from a [NumCol]. I can write it for, say, Pair:
get_pairs :: [NumCol] -> [NumCol]
get_pairs = filter is_pair
where is_pair (Pair _ _) = True
is_pair _ = False
This works, but it's not generic. I have to write a separate function for is_single, is_lots, etc.
I wish instead I could write:
get_pairs = filter (== Pair)
But this only works for type constructors that take no arguments (i.e. Empty).
So the question is, how can I write a function that takes a value and a constructor, and returns whether the value matches the constructor?
At least get_pairs itself can be defined relatively simply by using a list comprehension to filter instead:
get_pairs xs = [x | x#Pair {} <- xs]
For a more general solution of matching constructors, you can use prisms from the lens package:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import Control.Lens.Extras (is)
data NumCol = Empty |
Single Int |
Pair Int Int |
Lots [Int]
-- Uses Template Haskell to create the Prisms _Empty, _Single, _Pair and _Lots
-- corresponding to your constructors
makePrisms ''NumCol
get_pairs :: [NumCol] -> [NumCol]
get_pairs = filter (is _Pair)
Tags of tagged unions ought to be first-class values, and with a wee bit of effort, they are.
Jiggery-pokery alert:
{-# LANGUAGE GADTs, DataKinds, KindSignatures,
TypeFamilies, PolyKinds, FlexibleInstances,
PatternSynonyms
#-}
Step one: define type-level versions of the tags.
data TagType = EmptyTag | SingleTag | PairTag | LotsTag
Step two: define value-level witnesses for the representability of the type-level tags. Richard Eisenberg's Singletons library will do this for you. I mean something like this:
data Tag :: TagType -> * where
EmptyT :: Tag EmptyTag
SingleT :: Tag SingleTag
PairT :: Tag PairTag
LotsT :: Tag LotsTag
And now we can say what stuff we expect to find associated with a given tag.
type family Stuff (t :: TagType) :: * where
Stuff EmptyTag = ()
Stuff SingleTag = Int
Stuff PairTag = (Int, Int)
Stuff LotsTag = [Int]
So we can refactor the type you first thought of
data NumCol :: * where
(:&) :: Tag t -> Stuff t -> NumCol
and use PatternSynonyms to recover the behaviour you had in mind:
pattern Empty = EmptyT :& ()
pattern Single i = SingleT :& i
pattern Pair i j = PairT :& (i, j)
pattern Lots is = LotsT :& is
So what's happened is that each constructor for NumCol has turned into a tag indexed by the kind of tag it's for. That is, constructor tags now live separately from the rest of the data, synchronized by a common index which ensures that the stuff associated with a tag matches the tag itself.
But we can talk about tags alone.
data Ex :: (k -> *) -> * where -- wish I could say newtype here
Witness :: p x -> Ex p
Now, Ex Tag, is the type of "runtime tags with a type level counterpart". It has an Eq instance
instance Eq (Ex Tag) where
Witness EmptyT == Witness EmptyT = True
Witness SingleT == Witness SingleT = True
Witness PairT == Witness PairT = True
Witness LotsT == Witness LotsT = True
_ == _ = False
Moreover, we can easily extract the tag of a NumCol.
numColTag :: NumCol -> Ex Tag
numColTag (n :& _) = Witness n
And that allows us to match your specification.
filter ((Witness PairT ==) . numColTag) :: [NumCol] -> [NumCol]
Which raises the question of whether your specification is actually what you need. The point is that detecting a tag entitles you an expectation of that tag's stuff. The output type [NumCol] doesn't do justice to the fact that you know you have just the pairs.
How might you tighten the type of your function and still deliver it?
One approach is to use DataTypeable and the Data.Data module. This approach relies on two autogenerated typeclass instances that carry metadata about the type for you: Typeable and Data. You can derive them with {-# LANGUAGE DeriveDataTypeable #-}:
data NumCol = Empty |
Single Int |
Pair Int Int |
Lots [Int] deriving (Typeable, Data)
Now we have a toConstr function which, given a value, gives us a representation of its constructor:
toConstr :: Data a => a -> Constr
This makes it easy to compare two terms just by their constructors. The only remaining problem is that we need a value to compare against when we define our predicate! We can always just create a dummy value with undefined, but that's a bit ugly:
is_pair x = toConstr x == toConstr (Pair undefined undefined)
So the final thing we'll do is define a handy little class that automates this. The basic idea is to call toConstr on non-function values and recurse on any functions by first passing in undefined.
class Constrable a where
constr :: a -> Constr
instance Data a => Constrable a where
constr = toConstr
instance Constrable a => Constrable (b -> a) where
constr f = constr (f undefined)
This relies on FlexibleInstance, OverlappingInstances and UndecidableInstances, so it might be a bit evil, but, using the (in)famous eyeball theorem, it should be fine. Unless you add more instances or try to use it with something that isn't a constructor. Then it might blow up. Violently. No promises.
Finally, with the evil neatly contained, we can write an "equal by constructor" operator:
(=|=) :: (Data a, Constrable b) => a -> b -> Bool
e =|= c = toConstr e == constr c
(The =|= operator is a bit of a mnemonic, because constructors are syntactically defined with a |.)
Now you can write almost exactly what you wanted!
filter (=|= Pair)
Also, maybe you'd want to turn off the monomorphism restriction. In fact, here's the list of extensions I enabled that you can just use:
{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, NoMonomorphismRestriction, OverlappingInstances, UndecidableInstances #-}
Yeah, it's a lot. But that's what I'm willing to sacrifice for the cause. Of not writing extra undefineds.
Honestly, if you don't mind relying on lens (but boy is that dependency a doozy), you should just go with the prism approach. The only thing to recommend mine is that you get to use the amusingly named Data.Data.Data class.

Determine whether a value is a function in Haskell

Is it possible to write a function isFunc :: a -> Bool to determine whether an arbitrary value is a function (of any kind) such that
foo :: Int -> Int
bar :: Char -> Char -> Char
> isFunc foo
True
> isFunc bar
True
> isFunc 3
False
> isFunc 'a'
False
I'm using Data.Dynamic so I can't determine the type in advance.
What are you asking for and what you need to do with Data.Dynamic seem to be different things. You need to know the exact type of value before extracting it with fromDyn/fromDynamic. To determine whether Dynamic contains a function value you need to analyze TypeRep:
isFuncDynamic x = typeRepTyCon (dynTypeRep x) == typeRepTyCon (typeOf2 id)
(Forgive me if this is not the most concise implementation.)
Parametricity says no. The only functions of type
a -> Bool
are constant functions.
However, with a bit of ad hoc polymorphism and a bit more chutzpah, you can do this:
{-# LANGUAGE OverlappingInstances, FlexibleInstances #-}
class Sick x where
isFunc :: x -> Bool
instance Sick (a -> b) where
isFunc _ = True
instance Sick x where
isFunc _ = False
and then it looks like you have
*Sick> isFunc 3
False
*Sick> isFunc id
True
But it does seem like a peculiar thing to do. What use is the resulting Bool to you?

Checking for a particular data constructor

Let's say that I defined my own data-Type like
data MyData = A arg| B arg2| C arg3
How would I write a function (for instance: isMyDataType) that checks wether the given argument is one out of the particular types in MyData and successively returns a boolean (True or False) , e.g. typing in Ghci:
isMyDataType B returns True and isMyDataType Int returns False.
I believe you want functions to test for particular constructors:
isA :: MyData -> Bool
isB :: MyData -> Bool
If so, then you can write these yourself or derive them. The implementation would look like:
isA (A _) = True
isA _ = False
isB (B _) = True
isB _ = False
To derive them automatically, just use the derive library and add, in your source code:
{-# LANGUAGE TemplateHaskell #-}
import Data.DeriveTH
data MyData = ...
deriving (Eq, Ord, Show}
derive makeIs ''MyData
-- Older GHCs require more syntax: $( derive makeIs ''MyData)
Also note: your data declaration is invalid, the name must be capitalized, MyData instead of myData.
Finally, this whole answer is based on the assumption you want to test constructors, not data types as you said (which are statically checked at compile time, as Tarrasch said).
Haskell always checks that the types makes sense. The compiler would complain immediately if you wrote isMyDataType 4, because 4 is not of type MyData, it's of type Int.
I'm not sure this is what you asked for, but either way I strongly suggest for you to try out what you've asked here in practice, so you can see for yourself. Most important is that you check out type signatures in haskell, it is key for learning haskell.
You can use Maybes. You can create a set of functions that check for each of the types
getA, getB, getC :: MyData a -> Maybe a
getA x = case x of {(A v) -> Just v; _ -> Nothing}
getB x = case x of {(B v) -> Just v; _ -> Nothing}
getC x = case x of {(C v) -> Just v; _ -> Nothing}
This affords some practical idioms for certain tasks:
allAs :: [MyData a] -> [a]
allAs xs = mapMaybe getA xs
printIfA :: Show a => MyData a -> IO ()
printIfA x = maybe (return ()) print $ getA x

Resources