Use parts of constructor for deriving instance in Haskell data - haskell

I need to derive Eq for a data, but for some constructors I want to ignore some fields.
The data is for representing DataTypes (we are developing a compiler):
data DataType
= Int | Float | Bool | Char | Range | Type
| String Width
| Record (Lexeme Identifier) (Seq Field) Width
| Union (Lexeme Identifier) (Seq Field) Width
| Array (Lexeme DataType) (Lexeme Expression) Width
| UserDef (Lexeme Identifier)
| Void | TypeError
deriving (Ord)
I need to ignore the Width field from every contstructor it appears in.

You cannot derive Eq if you wish to use custom Eq semantics. You must write an instance by hand.
A common trick is to:
define a DataType' that drops the fields you wish to ignore
derive Eq for this
define Eq for DataType as a == b = toDataType' a == toDataType' b
This at least makes it less ad hoc, capturing the different Eq semantics in its own type, where it /can/ be derived.

Another approach from Don's is to use a wrapper type to encode the instances you want for the special fields:
newtype Metadata a = Metadata { unMetadata :: a }
instance Eq (Metadata a) where
(==) _ _ = True
instance Ord (Metadata a) where
compare _ _ = EQ
You can then replace all the Width's in your DataType definition with Metadata Width and derive the instances.
data DataType
= Int | Float | Bool | Char | Range | Type
| String (Metadata Width)
| Record (Lexeme Identifier) (Seq Field) (Metadata Width)
| Union (Lexeme Identifier) (Seq Field) (Metadata Width)
| Array (Lexeme DataType) (Lexeme Expression) (Metadata Width)
| UserDef (Lexeme Identifier)
| Void | TypeError
deriving (Eq, Ord)
This solution makes your DataType definition a bit more verbose (and more explicit?) but requires wrapping and unwrapping when using the Width values.

You could write your own instance of Eq:
instance Eq DataType where
Int == Int = True
Float == Float = True
Bool == Bool = True
Char == Char = True
Range == Range = True
Type == Type = True
(String _) == (String _) = True
(Record l1 s1 _) == (Record l2 s2 _) = (l1 == l2) && (s1 == s2)
(Union l1 s1 _) == (Union l2 s2 _) = (l1 == l2) && (s1 == s2)
(Array l1 e1 _) == (Array l1 e1 _) = (l1 == l2) && (e1 == e2)
(UserDef i1) == (UserDef i2) = i1 == i2
Void == Void = True
TypeError == TypeError = True
_ == _ = False

Related

Modifying a list using recursion

I have a list with elements of type LocalType (defined below), I wish to modify this list in function of which subtptype the element is belonging too.
An element of type End stays in the list of type End. For an element of type Prl (End Bar End), the first End shall stay in the list, the second End shall be appended to the list.
E.g [End, (Prl s Bar ss)] -> [End, s, ss]
E.g [End, End Bar End] -> [End, End, End]
This is how I thought of implementing it,
sepTimes :: [LocalType] -> [LocalType]
sepTimes(x:[]) = [x]
sepTimes(x:xs)
| x == End = sepTimes (x:xs)
| x == (Prl s Bar ss) = do
sepTimes (s:xs)
sepTimes (ss:xs)
As the error messages states, I am unable to retrive the elements s and ss corresponding to End and End in the example of Prl (End Bar End).
app\Sequents.hs:44:17: error: Variable not in scope: s :: LocalType
|
44 | | x == (Prl s Bar ss) = do
| ^
app\Sequents.hs:44:23: error:
* Variable not in scope: ss :: LocalType
* Perhaps you meant `xs' (line 42)
|
44 | | x == (Prl s Bar ss) = do
| ^^
app\Sequents.hs:45:19: error: Variable not in scope: s :: LocalType
|
45 | sepTimes (s:xs)
| ^
app\Sequents.hs:46:19: error:
* Variable not in scope: ss :: LocalType
* Perhaps you meant `xs' (line 42)
|
46 | sepTimes (ss:xs)
| ^^
Here are the defined datatypes :
data Seperator = Bar | BackAmpersand
deriving (Show, Eq, Ord, Read)
data LocalType = End
| Prl LocalType Seperator LocalType
deriving (Eq, Ord, Read)
You're confusing equality checks with pattern matching. Intuitively, all of the following should be the same:
f :: Either Int Char -> String
f (Left i) = show i
f (Right c) = [c]
f :: Either Int Char -> String
f x = case x of
Left i -> show i
Right c -> [c]
f :: Either Int Char -> String
f x
| x==Left i = show i -- what?
| x==Right c = [c]
But actually, only the first two are equivalent, the last one doesn't work. Why? You can't match a variable out of an equality statement. That may work in some logical languages where the equality is propositional, but Haskell's == operator is simply boolean: it takes two fully known values and tells you whether or not they're exactly the same. I.e., in order to be able to write x==Left i, the variable i must already be defined.

Haskell, why do I get a prelude undefined error?

this is an exercise where I have to create my own universe of things in Haskell for a logic course. This was given to us already:
data Thing = A | B | C | D | E deriving (Eq,Show)
things :: [Thing]
things = [ A, B, C, D, E ]
data Colour = Amber | Blue deriving Eq
colour :: Thing -> Colour
colour A = Amber
colour B = Amber
colour C = Amber
colour D = Blue
colour E = Amber
data Shape = Square | Disc deriving Eq
shape :: Thing -> Shape
shape A = Square
shape B = Square
shape C = Disc
shape D = Square
shape E = Square
data Size = Big | Small deriving Eq
size :: Thing -> Size
size A = Big
size B = Big
size C = Big
size D = Big
size E = Small
data Border = Thin | Thick deriving Eq
border :: Thing -> Border
border A = Thick
border B = Thin
border C = Thick
border D = Thick
border E = Thick
type Predicate u = u -> Bool
isAmber :: Predicate Thing
isAmber x = colour x == Amber
isBlue :: Predicate Thing
isBlue x = colour x == Blue
isSquare :: Predicate Thing
isSquare x = shape x == Square
isDisc :: Predicate Thing
isDisc x = shape x == Disc
isBig :: Predicate Thing
isBig x = size x == Big
isSmall :: Predicate Thing
isSmall x = size x == Small
hasThinBorder :: Predicate Thing
hasThinBorder x = border x == Thin
hasThickBorder :: Predicate Thing
hasThickBorder x = border x == Thick
The following function was also given as an example of predicate negation :
neg :: Predicate u -> Predicate u
(neg a) x = not (a x)
I have to write 2 functions, one for conjunction (only true & true = true, all else is false) and disjunction (only false & false = true). I was pretty sure that this was correct, but i get the prelude undefined error when I call:
(|:|) :: Predicate u -> Predicate u -> Predicate u
(a |:| b) x = (a x) && (b x)
(&:&) :: Predicate u -> Predicate u -> Predicate u
(a &:& b) x = (a x) || (b x)
(|=) :: Predicate Thing -> Predicate Thing -> Bool
a |= b = [thinga | thinga <- things, a thinga] == [thingb | thingb <- things, b thingb, a thingb]
(|/=) :: Predicate Thing -> Predicate Thing -> Bool
a |/= b = not (a |= b)
But also, the instructions say that calling the following should work, and i do not understand how, since the x formal parameter is never used...
isBig &:& isAmber |= isDisc
That should return either true or false apparently
Example of Error
*Main> :reload
Ok, one module loaded.
*Main> isSmall |= isDisc
False
*Main> (neg isAmber) C
False
*Main> (isBig &:& isAmber) |= isDisc
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
error, called at libraries\base\GHC\Err.hs:79:14 in base:GHC.Err
undefined, called at things.hs:89:15 in main:Main
I'm focusing on this part:
and i do not understand how, since the x formal parameter is never
used...
isBig &:& isAmber |= isDisc
That should return either true or false apparently
The value of x is chosen by |=, which will call both predicates isBig &:& isAmber and isDisc with all the x in list things.
Expanding the definitions:
isBig &:& isAmber |= isDisc
= -- according to the definition of |=
[thinga | thinga <- things, (isBig &:& isAmber) thinga]
==
[thingb | thingb <- things, isDisc thingb, (isBig &:& isAmber) thingb]
= -- according to the definition of &:&
[thinga | thinga <- things, isBig thinga && isAmber thinga]
==
[thingb | thingb <- things, isDisc thingb, isBig thingb && isAmber thingb]
=
[ A, B, C ] -- i.e., list of all things which are both big and amber
==
[ C ] -- i.e., list of all things which are discs, big, and amber
=
False -- the two lists are not the same list
So, it's thinga and thingb that are passed as x. Those variables, in turn, assume all the values inside the list things, i.e. [A,B,C,D,E].

How to check if coords(x,y) are valid on a board in Haskell

I have a function
isValid :: CoOrd -> Bool
Where CoOrd is a tuple pair (x,y)
The boards size is ['a'..'h'] ['1'..'8'] so I want to check if the given CoOrds are valid for this board (CoOrds x < ['a'..'h'], CoOrds y ['1'..'8'])
I'm fine with the logic of this question, its just the syntax as I'm new to haskell, so I'm looking for something like this
if (CoOrd(x _) == ['a'..'h'])
if (CoOrd(_ y) == ['1'..'8'])
return True
else return False
The basic approach is to use direct comparisons:
isValid :: CoOrd -> Bool
isValid (x,y) = x >= 'a' && x <= 'h' && y >= '1' && y <= '8'
A more advanced alternative is to exploit Data.Ix.inRange:
import Data.Ix
isValid :: CoOrd -> Bool
isValid = inRange (('a','1'),('h','8'))
You can also use elem, as others pointed out, but elem will scan the whole list and perform pointwise comparisons (8+8 comparisons, in the worst case), while the methods above will only do four comparisons.
Finally, a few comments on your original code:
Don't use return in Haskell unless you are writing monadic code
Don't use if condition then True else False -- that's noise, and it is equivalent to conditions. Consider using boolean operators instead, which is often simpler.
Why not make some new types for your X and Y coordinates so the type checker gives you a static guarantee that any CoOrd value is correct?
For example, I think you have type CoOrd = (Char,Int). Instead try:
data XCo = A | B | C | D | E | F | G | H deriving (Eq,Ord,Show,Enum)
data YCo = Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 | Y8 deriving (Eq,Ord,Enum)
instance Show YCo where
show y = show (fromEnum y + 1)
type CoOrd = (XCo,YCo)
And now anywhere you were using character literals like 'a', 'b' etc you use A, B etc. Same with the numbers and the Y axis - 1 becomes Y1 etc.
isValid (x,y) = x `elem` ['a'..'h'] && y `elem` ['1'..'8']
In addition to the other answers instead of using tuples you may define a new type, for example ChessBoard.
Since you are in need of checking the validity of the entered position it might be wise to make it Maybe ChessBoard type as well.
Accordingly you may come up with something like
module ChessBoard (ChessBoard, chessBoard) where
data ChessBoard = CB Char Int deriving (Eq, Ord, Show)
chessBoard :: Char -> Int -> Maybe ChessBoard
chessBoard c n | elem c ['a'..'h'] && elem n [1..8] = Just (CB c n)
| otherwise = Nothing
Here as you may notice we are not exporting the data constructor CB Char Int so the only way to create your chess board position data is through the chessBoard function and there will be no illegal board positions.
I mean;
*Main> chessBoard 'a' 3
Just (CB 'a' 3)
*Main> chessBoard 'h' 9
Nothing
*Main> let pos = Just (CB 'a' 11) -- trying to assign an illegal position directly
<interactive>:259:17: error:
Data constructor not in scope: CB :: Char -> Integer -> a

Create a Reduced Ordered Binary Decision Diagram from boolean expression in Haskell

Assuming the following definitions:
type Index = Int
data BExp = Prim Bool | IdRef Index | Not BExp | And BExp BExp | Or BExp BExp
deriving (Eq, Ord, Show)
type NodeId = Int
type BDDNode = (NodeId, (Index, NodeId, NodeId))
type BDD = (NodeId, [BDDNode])
I want to build a ROBDD from a boolean expression. So far, I've been able to construct a BDD that doesn't satisfy the no-redundancy or sharing properties.
buildBDD :: BExp -> [Index] -> BDD
buildBDD e idxs
= buildBDD' e 2 idxs
buildBDD' :: BExp -> NodeId -> [Index] -> BDD
buildBDD' (Prim bool) _ []
| bool = (1, [])
| otherwise = (0, [])
buildBDD' e nodeId (idx : idxs)
= (nodeId, [newNode] ++ tl ++ tr)
where
newNode = (nodeId, (idx, il, ir))
(il, tl) = buildBDD' (restrict e idx False) (2 * nodeId) idxs
(ir, tr) = buildBDD' (restrict e idx True) (2 * nodeId + 1) idxs
The naming and style may not be the best, as this is still work in progress.
The nodes are internally represented by a unique id. It starts from 2. The root node of the left subtree will be labelled 2n and the root node of the right subtree will be labelled 2n + 1.
The function will take as input the boolean expression and a list of indices for the variables that appear in the expression.
For example, for the following expression:
And (IdRef 7) (Or (IdRef 2) (Not (IdRef 3)))
The call buildBDD bexp [2,3,7] will return
(2,[(2,(2,4,5)),(4,(3,8,9)),(8,(7,0,1)),(9,(7,0,0)),(5,(3,10,11)),(10,(7,0,1)),
(11,(7,0,1))])
I've made the following changes to account for the no-redundancy property (this has not been tested thoroughly, but appears to be working)
checkEqual (_, l, r)
| l == r = True
| otherwise = False
getElemFromTuple (_, _, e)
= e
getTuple = snd . head
buildROBDD' e nodeId (idx : idxs)
= (nodeId, [newNode] ++ left ++ right)
where
newNode = (nodeId, (idx, lId, rId))
(il, tl) = buildROBDD' (restrict e idx False) (2 * nodeId) idxs
(ir, tr) = buildROBDD' (restrict e idx True) (2 * nodeId + 1) idxs
lId = if (not . null) tl && (checkEqual . getTuple) tl then (getElemFromTuple . getTuple) tl else il
rId = if (not . null) tr && (checkEqual . getTuple) tr then (getElemFromTuple . getTuple) tr else ir
left = if (not . null) tl && (checkEqual . getTuple) tl then [] else tl
right = if (not . null) tr && (checkEqual . getTuple) tr then [] else tr
(excuse the clumsy expressions above)
However, I don't know how to approach the sharing property, especially because the shared node might be anywhere in the graph and I am not storing the current tree. The formula for the unique node ids can be changed if needed.
Note: this is meant as an exercise, so the types and style involved might not be optimal. I am also not supposed to change them (I am free to change the function though).

Haskell Data type 3-address code

I'm trying to create a compiler into an intermediate language, and for that purpose I created the following data types:
data C = Atr Var Var
deriving(Show)
data E = Var Op Var
deriving (Show)
data Var = V String
| N Int
deriving (Show)
data Op = OpPlus
| OpMinus
| OpMult
| OpDiv
deriving (Show)
But I'm having problems when I use the E data type, for example:
compileE :: Exp -> Int -> [(String,Int)] ->(Int,Var,[C])
compileE ( Plus e1 e2 ) k regs = let (v1,t1,l1)= (compileE e1 k regs);
( v2,t2,l2 ) =( compileE e2 v1 regs);
t = new_Var v2
in (v2+1,V t, l1 ++ l2 ++ [Atr (V t) (t1 OpPlus t2)])
In the expression "t1 OpPlus t2", it says t1 is applied to too many arguments. That would make sense since t1 doesn't exist in the data type, but t1 is a Var and that expression should be in the Var Op Var form.
Any sugestions on a work around?
EDIT:
Aparently my english sucked and i didn't explain well my question:
My intermediate language needs to be defined using this rule, among others: "E<- Var Op Var" where E is an expression, Var could be an int or string (case of variable) and Op the symbol im using. At the end of the compileE function, im trying to concatenate the previous expressions ( l1 and l2) with the current one to create the [C] list.
My problem is that I'm not being able to add the "Var Op Var" format (t1 OpPlus t2) because its listing t1 as a function and not as part of the Var data type.
It looks like you forgot to give E a data constructor of its own. data E = Var Op Var defines Var as the data constructor for E, and it takes two arguments (one Op, one Var). Because Var is also the name of a separate type, this is not a good idea. It seems that you meant to write E = E' Var Op Var, where E' is some new name (it could even be E!), after which (assuming I'm reading your intent correctly) t1 OpPlus t2 becomes E' t1 OpPlus t2.
Note that, even after you fix this, your code still won't work, as it looks like you're trying to use an E value as the second argument to Atr, even though the second argument should be a Var. What are you really trying to do there?
data Exp = Plus Exp Exp
| Name String
| Const Int
data C = Atr Var E
deriving(Show)
data E = E Var Op Var
deriving (Show)
data Var = V String
| N Int
deriving (Show)
data Op = OpPlus
| OpMinus
| OpMult
| OpDiv
deriving (Show)
new_Var :: Int -> String
new_Var i = "sym" ++ show i
compileE :: Exp -> Int -> [(String,Int)] ->(Int,Var,[C])
compileE (Name s) k regs = (k, V s, [])
compileE (Const i) k regs = (k, N i, [])
compileE (Plus e1 e2) k regs = (v2+1, V t, l1 ++ l2 ++ [Atr (V t) (E t1 OpPlus t2)])
where (v1,t1,l1) = compileE e1 k regs
(v2,t2,l2) = compileE e2 v1 regs
t = new_Var v2
The above passes compilation. I made up an Exp type to match more or less what I thought would be the AST compileE is expecting. The end result corresponds to the signature of your function. new_Var generates symbols for your variables. At this point you probably don't need yet the regs variable; it will probably be useful at a later stage, when your compiler does the register allocation phase.

Resources