Haskell: Understanding custom data types - haskell

I am trying to make my own custom data type in Haskell.
I have the following data types:
type Length = Integer
type Rotation = Integer
data Colour = Colour { red, green, blue, alpha :: Int }
deriving (Show, Eq)
I am trying to make a custom data type that can be either one of the data types above. I have the following:
data Special
= L Length
| R Rotation
| Col Colour
deriving (Show, Eq)
However, I would like to be able to extract the Length, Rotation and Colour value if I have an instance of the Special data type.
If I had:
L length
Would length here be of type Special or of type Length? If length is of type Special is there any way to extract it so it's of type Length?
For example, is the following code valid?
takeL (x:xs)
| x == (L length) = length
Any insights are appreciated.

For the expression L length to be valid, length would have to be a Length (because L :: Length -> Special).
takeL (x:xs)
| x == (L length) = length
is not valid. Unless you've redefined length somewhere, length is a function [a] -> Int from the standard library, so L length is a type error.
I think what you're trying to do here is just pattern matching:
takeL (L length : xs) = length

The data type definition
data Special =
reads: Special is a new type such that to create a value of type Special,
L Length
call L l where l is a value of type Length; or
| R Rotation
call R r where r is a value of type Rotation; or
| Col Colour
call Col c where c is a value of type Colour.
To analyze a value of type Special, there are three cases to consider:
foo :: Special -> ...
foo val =
case val of
L l -> ...
l is a value of type Length, in the case val was actually L l; or
R r -> ...
r is a value of type Rotation, in the case val was actually R r; or
Col c -> ...
c is a value of type Colour, in the case val was actually Col c.
The case syntax in function definitions can also be expressed with the pattern based clauses:
foo :: Special -> ...
foo (L l) = ...
foo (R r) = ...
foo (Col c) = ...

Related

Couldn't match type Char with [Char], Haskell

I have recently started learning Haskell and I have encountered a problem with dictionaries. I use a key to get the integer number from the dictionary, and GHCi prints an error "Couldn't match type Char with [Char]" on the line where I use a first element of the string as key for a dictionary. Here is the code:
import Data.Map
mapRomantoInt :: Map String Int
mapRomantoInt = fromList[("I",1),("V",5),("IX",9),("X",10),("L",50),("C",100),("D",500),("M",1000)]
romanToInt :: String -> Int
romanToInt _ = 0
romanToInt c = if length c == 1 then mapRomantoInt ! head c else
let first = mapRomantoInt ! head c
second = mapRomantoInt ! (c !! 1)
others = romanToInt(tail c)
in if first < second then others - first else others + first
In Haskell, String is a synonym for [Char].
The c in romanToInt has the type String, i.e. [Char].
The type of head is [a] -> a, so head c has the type Char.
The type of (!) is Ord k => Map k a -> k -> a. In this case, mapRomantoInt has the type Map String Int, so the k in question must be String.
The function call mapRomantoInt ! head c, however, tries to pass a Char instead of a [Char] (String).
There are other problems with the code in the OP, but try to fix the compilation error(s) first.

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

Neighborhood of a mathematical expression using Haskell

I'm trying to implement with Haskell an algorithm to manipulate mathematical expressions.
I have this data type :
data Exp = Var String | IVal Int | Add Exp Exp
This will be enough for my question.
Given a set of expression transformations, for example :
(Add a b) => (Add b a)
(Add (Add a b) c) => (Add a (Add b c))
And an expression, for example : x = (Add (Add x y) (Add z t)), I want to find all expressions in the neighborhood of x. Given that neighborhood of x is defined as: y in Neighborhood(x) if y can be reached from x within a single transformation.
I am new to Haskell. I am not even sure Haskell is the right tool for this job.
The final goal is to get a function : equivalent x which returns a set of all expressions that are equivalent to x. In other words, the set of all expressions that are in the closure of the neighborhood of x (given a set of transformations).
Right now, I have the following :
import Data.List(nub)
import Data.Set
data Exp = IVal Int
| Scalar String
| Add Exp Exp
deriving (Show, Eq, Ord)
commu (Add a b) = (Add b a)
commu x = x
assoc (Add (Add a b) c) = (Add a (Add b c))
assoc (Add a (Add b c)) = (Add (Add a b) c)
assoc x = x
neighbors x = [commu x, assoc x]
equiv :: [Exp] -> [Exp]
equiv closure
| closure == closureUntilNow = closure
| otherwise = equiv closureUntilNow
where closureUntilNow = nub $ closure ++ concat [neighbors x|x<-closure]
But It's probably slower than needed (nub is O(n^2)) and some terms are missing.
For example, if you have f = (x+y)+z, then, you will not get (x+z)+y, and some others.
Imports, etc. below. I'll be using the multiset package.
import Control.Monad
import Data.MultiSet as M
data Exp = Var String | IVal Int | Add Exp Exp deriving (Eq, Ord, Show, Read)
A bit of paper-and-pencil work shows the following fact: expressions e1 and e2 are in the congruence closure of your relation iff the multiset of leaves are equal. By leaves, I mean the Var and IVal values, e.g. the output of the following function:
leaves :: Exp -> MultiSet Exp
leaves (Add a b) = leaves a `union` leaves b
leaves e = singleton e
So this suggests a nice clean way to generate all the elements in a particular value's neighborhood (without attempting to generate any duplicates in the first place). First, generate the multiset of leaves; then nondeterministically choose a partition of the multiset and recurse. The code to generate partitions might look like this:
partitions :: Ord k => MultiSet k -> [(MultiSet k, MultiSet k)]
partitions = go . toOccurList where
go [] = [(empty, empty)]
go ((k, n):bag) = do
n' <- [0..n]
(left, right) <- go bag
return (insertMany k n' left, insertMany k (n-n') right)
Actually, we only want partitions where both the left and right part are non-empty. But we'll check that after we've generated them all; it's cheap, as there's only two that aren't like that per invocation of partitions. So now we can generate the whole neighborhood in one fell swoop:
neighborhood :: Exp -> [Exp]
neighborhood = go . leaves where
full = guard . not . M.null
go m
| size m == 1 = toList m
| otherwise = do
(leftBag, rightBag) <- partitions m
full leftBag
full rightBag
left <- go leftBag
right <- go rightBag
return (Add left right)
By the way, the reason you're not getting all the terms is because you're generating the reflexive, transitive closure but not the congruence closure: you need to apply your rewrite rules deep in the term, not just at the top level.

Haskell beginner: Data decl. errors

Hello I am trying to write a very simple function in Haskell. However I can't get "ghci" to accept my code.
data Field = A1 Int deriving (Show)
data FieldList = FL [Field] | Name String deriving (Show)
t :: Field
t = A1 1
u :: Int -> FieldList
u 0 = FL []
u n = FL [t]:(u (n-1))
And the error I get is this:
test.hs:9:7:
Couldn't match expected type `FieldList' with actual type `[a0]'
In the expression: (FL [t]) : (u (n - 1))
In an equation for `u': u n = (FL [t]) : (u (n - 1))
Can someone point me in the right direction?
Thanks!
Looking at the last line:
u n = FL [t]:(u (n-1))
u has the type Int -> FieldList. n is an Int, so (n - 1) is also an Int. u (n-1) would therefor be a FieldList.
Function application has a higher precedence than operators, so the above line is equivalent to:
u n = (FL [t]) : (u (n - 1) )
FL [t] is a FieldList.
However, (:) has the type a -> [a] -> [a]. You can see the types don't match, so that is what is causing the problem.
What you probably want to do is build up the list of Fields (having type [Field]), and then turning that into a FieldList. Here is some stub code:
u :: Int -> FieldList
u n = FL (uHelper n)
uHelper :: Int -> [Field]
uHelper = ... -- write this function
The error says (FL [t]) : (u (n - 1)) which says that you are trying the List cons function on
FL [t] which is not a list hence you cannot cons with it.
I am not sure why you have created a FieldList as a new data type which allows a FieldList to be either a List of Field OR a string (which is created using Name constructor) which sort of doesn't make logical sense.
What you can do is make FieldList as:
type FieldList = [Field]
And then your function would become:
u :: Int -> FieldList
u 0 = []
u n = t : (u (n-1))
There are two problems with your code:
The first argument of list cons (:) is an element, not a list, thus: t : ... not [t] : ...
You must unwrap the FieldList first to get [Field]. Then you can prepend t to it.
You want your last line to be
u n = case u (n-1) of FL xx -> FL (t:xx)
That would of course fail to pattern match if the field list is a Name so I would agree with Ankur that there might be a problem with the design...

What is being passed in?

In the code:
oneChar :: Char -> Doc
oneChar c = case lookup c simpleEscapes of
Just r -> text r
Nothing | mustEscape c -> hexEscape c
| otherwise -> char c
where mustEscape c = c < ' ' || c == '\x7f' || c > '\xff'
simpleEscapes :: [(Char, String)]
simpleEscapes = zipWith ch "\b\n\f\r\t\\\"/" "bnfrt\\\"/"
where ch a b = (a, ['\\',b])
r isn't being passed to oneChar. Where does r come from?
lookup c simpleEscapes returns a Maybe String value, which can be either Nothing or Just <a string>. r is the string contained in the Just, as defined by the line:
Just r -> text r
The case keyword introduces a pattern match, which has the form case EXPR of (PATTERN -> EXPR)+. So Just r is a pattern, that matches the result of lookup c simpleEscapes of. In a pattern, variables can be bound. Basically this means, if lookup c simpleEscapes of returns a Just then r will be bound to the value inside that Just and the result of the expression will be text r.
If you're asking where the identifier is introduced, it's bound by the pattern match in the case statement, the same way the identifier c is bound by the pattern match in the function definition.
Any pattern match can introduce a new identifier for the associated expression:
(\(Just x) -> x) foo
let (Just x) = foo in x
f (Just x) = x
case foo of
Just x -> x
...all of those introduce a new identifier named x. In fact, they're all pretty much equivalent, because the compiler converts all of them into case blocks under the hood.
You're using a case statement on the value returned by lookup c simpleEscapes, which is of type Maybe. Maybe has two data constructors: Just and Nothing. The Just data constructor is parameterized by one value, the Nothing data constructor has no parameters.
So in this case, r is the formal parameter to the Just data constructor: its the actual value in the returned value from lookup.

Resources