haskell writing constructors that do work in them - haskell

i have a few questions
Im writing this constructor called rope which i have like this
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
deriving Show
First off when i make a TextRope like this
*Main> let s =TextRope "why"
*Main> s
TextRope {ropeText = "why"}
*Main>
when i do s i want to just get the string of the constructor which is why and im not really sure about that.
Also curious about concat and sub constructors. Specifically it seems like to me you are calling these two constructors there is things happening, you are returning the result of concatenating rope 1 and rope 2 together, im not sure how to describe that in this language, you are defining the data structure but somehow the return of that is a result that has to be calculated by the structure
Here are some examples of what how these functions work
> let tr = TextRope "Hello,"
> let sr = TextRope " world!"
> let hw = ConcatRope tr sr
> let ow = SubRope hw 4 4
> tr
Hello,
> sr
world!
> hw
Hello, world!
Sort of confused overall, new to haskell constructors and datatypes, so some pointers would be helpful (not c pointers though!)

Data constructors never do work. They only hold the data you pass into them. If you want work to be done, you should define what are called smart constructors, which are just functions that perform some operation before passing it to the actual constructor. An example might be
data Fraction = Fraction
{ numerator :: Int
, denominator :: Int
} deriving (Eq)
(%) :: Int -> Int -> Fraction
x % y =
let (a, b) = reduce x y
in Fraction a b
-- Reduces a fraction to it's simplest terms
reduce :: Int -> Int -> (Int, Int)
reduce num den = undefined
Here you wouldn't export the Fraction constructor from your module, just the % function that constructs one in the most reduced form.
The other problem you have is that you want your constructors to print out differently. You can achieve this by not deriving Show. However, I will warn that the Haskell convention is that show . read = read . show = id, which wouldn't hold for what you want to do. This isn't a strict convention, though, and there's nothing stopping you from doing something like:
data Rope = <your implementation minus the deriving Show bit>
instance Show Rope where
show (TextRope t) = t
show (ConcatRope r1 r2) = show r1 ++ show r2
show (SubRope r starting ending) = <exercise left to reader>
As an aside, I would recommend against having a sum type of records with different field names, this can lead to problems where your program type-checks but contains errors that can be caught at compile time if written differently. For example, what would happen if you had the code
> ropeText (ConcatRope (TextRope "Hello, ") (TextRope "world!"))
This would cause an error and crash your program! Instead, it looks like you just want a Rope type with concat and subRope functions, so you could implement it very simply as
data Rope = Rope String deriving (Eq)
concatRope :: Rope -> Rope -> Rope
concatRope (Rope r1) (Rope r2) = Rope (r1 ++ r2)
-- Why use Integer instead of Int? You might find it's easier to implement this function
subRope :: Rope -> Integer -> Integer -> Rope
subRope (Rope r) start end = Rope $ substr start end r
where substr s e text = <exercise left to reader>
Now there's absolutely no way to have an illegal rope operation, the only difference is now you have to use concatRope in place of ConcatRope and subRope in place of SubRope. You're guaranteed that these functions will do what you want, you don't have some complicated type that doesn't help you anyway.

if you don't implement your own show (not with auto-deriving) you will have a harder time getting what you want.
But if you do it's kindof easy:
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
instance Show Rope where
show (TextRope s) = s
show (ConcatRope a b) = show a ++ show b
I'm sure you'll find the implementation for the SubRope case youself ;)

Your example code and your example interactive results don't match. This is how you've defined Rope:
data Rope = TextRope{ropeText :: String}
| ConcatRope{rope1 :: Rope, rope2 :: Rope}
| SubRope{subRopetext :: Rope, starting :: Integer, ending :: Integer}
deriving Show
The deriving Show part is key there; we'll see how.
Later you show this example output:
> let tr = TextRope "Hello,"
> let sr = TextRope " world!"
> let hw = ConcatRope tr sr
> hw
Hello, world!
With the code that I just showed, actually, what you'll see is the following:
> hw
ConcatRope { rope1 = TextRope "Hello,", rope2 = TextRope " world!" }
The only way we could get the output that you describe is if we got rid of the deriving Show clause in your definition of Rope, and wrote this:
instance Show Rope where
show (TextRope text) = text
show (ConcatRope r1 r2) = show r1 ++ show r2
show (SubRope rope start end) = ...

Related

instance declaration and convert string to Maybe type

An guessing and answering game.
Each Card comprises a Suit, one of A,B,C,D,E,F,G, and a Rank, one of 1|2|3.
I need to have a function to guarantee input(String) whether is valid type. And also write an instance declaration so that the type is in the Show class.
I am not sure about the function toCard, how to express "String" in the function and meet it with the condition.
data Suit = A|B|C|D|E|F|G
deriving (Show , Eq)
data Rank = R1|R2|R3
deriving (Show, Eq)
data Card = Card Suit Rank
deriving (Show, Eq)
instance Show Card where show (Card a b)
= show a ++ show (tail show b)
toCard :: String -> Maybe Card
toCard all#(x:xs)
| (x=A|B|C|D|E|F)&&(xs==1|2|3) = Just Card
| otherwise = Nothing
edit toCard function, input should be any String, so i use a list expression, but it seems to be not correct, cause i try it in ghci, (x=A|B|C|D|E|F)&&(y==1|2|3) is not valid
1) Firstly,
instance Show Card where show (Card a b)
= show a ++ show (tail show b)
You have automatically derived a Show instance for Card, so this will conflict (you can only have 1 instance), and further it won't compile. The show should go on a new line, and tail should be applied to the result of show b.
instance Show Card where
show (Card a b) = show a ++ " " + tail (show b)
2) Secondly,
toCard :: String -> Maybe Card
toCard all#(x:xs)
| (x=A|B|C|D|E|F)&&(xs==1|2|3) = Just Card
| otherwise = Nothing
The syntax (x=A|B|C|D|E|F)&&(xs==1|2|3) is pretty wild, and certainly not valid Haskell. The closest approximation would be something like, x `elem` ['A','B','C','D','E','F'] && xs `elem` ["1","2","3"], but as you can see this rapidly becomes boilerplate-y. Also, Just Card makes no sense - you still need to use the x and xs to say what the card actually is! eg. Just $ Card x xs (though that still won't work because they're still character/string not Suit/Rank).
One solution would be to automatically derive a Read instance on Rank, Suit, and Card. However, the automatic derivation for read on Card would require you to input eg. "Card A R1", so let's try using the instance on Rank and Suit to let us write a parser for Cards that doesn't require prefixed "Card".
First attempt:
toCard :: String -> Maybe Card
toCard (x:xs) = Just $ Card (read [x] :: Suit) (read xs :: Rank)
Hmm, this doesn't really allow us to deal with bad inputs - problem being that read just throws errors instead of giving us a Maybe. Notice however that we use [x] rather than x because read applies to [Char] and x :: Char. Next attempt:
import Text.Read (readMaybe)
toCard :: String -> Maybe Card
toCard [] = Nothing
toCard (x:xs) = let mSuit = readMaybe [x] :: Suit
mRank = readMaybe xs :: Rank
in case (mSuit, mRank) of
(Just s, Just r) -> Just $ Card s r
_ -> Nothing
This copes better with bad inputs, but has started to get quite long. Here's two possible ways to shorten it again:
-- using the Maybe monad
toCard (x:xs) = do mSuit <- readMaybe [x]
mRank <- readMaybe xs
return $ Card mSuit mRank
-- using Applicative
toCard (x:xs) = Card <$> readMaybe [x] <*> readMaybe xs
A parser library, though it comes with a steeper learning curve, makes this simpler. For this example, we'll use Text.Parsec, from the parsec library. Import it, and define a type alias for using in defining your parsers.
import Text.Parsec
type Parser = Parsec String () -- boilerplate
Parsec String () indicates a type of parser that consumes a stream of characters, and can produce a value of type () after parsing is complete. (In this case, we only care about the parsing, not any computation done along side the parsing.)
For your core types, we'll define a Show instant by hand for Rank so that you don't need to strip the R off later. We'll also derive a Read instance for Suit to make it easier to convert a string like "A" to a Suit value like A.
data Suit = A|B|C|D|E|F|G deriving (Show, Read, Eq)
data Rank = R1|R2|R3 deriving (Eq)
-- Define Show yourself so you don't constantly have to remove the `R`
instance Show Rank where
show R1 = "1"
show R2 = "2"
show R3 = "3"
data Card = Card Suit Rank deriving Eq
instance Show Card where
show (Card s r) = show s ++ show r
With that out of the way, we can define some parsers for each type.
-- Because oneOf will fail if you don't get one
-- of the valid suit characters, read [s] is guaranteed
-- to succeed. Using read eliminates the need for a
-- large case statement like in rank, below.
suit :: Parser Suit
suit = do
s <- oneOf "ABCDEF"
return $ read [s]
rank :: Parser Rank
rank = do
n <- oneOf "123"
return $ case n of
'1' -> R1
'2' -> R2
'3' -> R3
-- A Card parser just combines the Suit and Rank parsers
card :: Parser Card
card = Card <$> suit <*> rank
-- parse returns an Either ParseError Card value;
-- you can ignore the exact error if the parser fails
-- to return Nothing instead.
toCard :: String -> Maybe Card
toCard s = case parse card "" s of
Left _ -> Nothing
Right c -> Just c
oneOf is a predefined parser that consumes exactly one of the items in the given list.
parse takes three arguments:
A parser
A "source name" (only used for error message; you can use any string you like)
The string to parse

Haskell Type Destructuring in Guards

I'm playing around with a toy project in Haskell. I'm implementing some data structures I've built in other languages before to familiarize myself with how they'd be built in Haskell. This isn't my first functional language, I've built a couple of projects like a Scheme interpreter in OCaml but I think my OCaml experience is coloring how I'm approaching this problem. Its' not terribly important, but may be useful for context, to know that the data structure I'm implementing is a PR-Quadtree.
What I want to do is match and destructure a type inside a guard, a la OCaml's match statement.
data Waypoint = WayPoint {
lat :: Float,
lon :: Float,
radius :: Float,
speed :: Float,
accel :: Float
} deriving (Show)
data Region = Region {
x :: Float,
y :: Float,
width :: Float
} deriving (Show)
data PRQuadtree = WhiteNode Region
| BlackNode Region Waypoint
| GreyNode {
topLeft :: PRQuadtree,
topRight :: PRQuadtree,
botLeft :: PRQuadtree,
botRight :: PRQuadtree,
region :: Region
} deriving (Show)
getRegion node
| BlackNode(r, _) = r
| WhiteNode(r) = r
| GreyNode = region node
The getRegion function is the one I am having problems with in particular. In case what I'm trying to do is unclear: I'd like to simple extract one element of the argument but that depends on which member of the algebraic data type the argument is. In OCaml I could do:
let getRegion node = match node with
| BlackNode(r, _) = r
| WhiteNode(r) = r
| GreyNode = region(node)
(or something very similar, my OCaml is a bit rusty now).
In Haskell however, this doesn't appear to bind r in scope of the RHS of the guard branch. I've tried to look up Pattern Guards, as they sound similar to what I might want to do, but I can't really grok whats going on here. Really I just want to get a binding from the LHS of the = to the RHS of the equals (depending on which branch of the guard we've gone down).
Whats the idiomatic Haskell way to do what I'm trying to do here?
It can be achieved as follows:
getRegion :: PRQuadtree -> Region
getRegion (BlackNode r _) = r
getRegion (WhiteNode r) = r
getRegion GreyNode{region=r} = r
or even as
getRegion :: PRQuadtree -> Region
getRegion x = case x of
BlackNode r _ -> r
WhiteNode r -> r
GreyNode{} -> region x
In Haskell, prepending a type signature is very idiomatic.
Another option is extending the region field to the other cases as well:
data PRQuadtree = WhiteNode { region :: Region }
| BlackNode { region :: Region , waypoint :: Waypoint }
| GreyNode {
topLeft :: PRQuadtree,
topRight :: PRQuadtree,
botLeft :: PRQuadtree,
botRight :: PRQuadtree,
region :: Region
} deriving (Show)
Now, region will work on all PRQuadtree values.
Haskell uses | as ML does when defining algebraic datatypes, to separate different constructors, but does not use it to separate case branches, which instead follow the syntax
case .. of { pat1 -> e1 ; pat2 -> e2 ; ... }
which can be replaced by indentation
case .. of
pat1 -> e1
pat2 -> e2
...
Also, note that partial field selectors are discouraged:
data A = A1 { foo :: Int } | A2
Above, foo A2 type checks but crashes. On the other hand, when a field is present in all the constructors, we do not face such risk.
You can also write:
getRegion x
| BlackNode y <- x -> ....
| Greynode{} <- x -> ....
but it is quite unidiomatic in this simple case.
However, in more complex programs, this pattern matching in guards can be very useful. You use multiple equations or case to distinguish the general cases, like shown by #chi. But then, you can detect special cases, like in the following made up example:
getRegion x = case x of
BlackNode{region}
| [(0,_)] <- filter (inRegion region) interestingPoints
-> -- region encloses exactly 1 interesting point on x axis
....
| otherwise = ....
where
interestingPoints = .....
inRegion :: Region -> Point -> Bool
GreyNode{} -> ....

Lens package with algebraic types

I was coding with with the lens package. Everything was going fine until I tried to access a certain field on an algebraic type:
import Control.Lens
data Type = A { _a :: Char } | B
makeLenses ''Type
test1 = _a (A 'a')
test2 = (A 'a') ^. a
No instance for (Data.Monoid.Monoid Char)
arising from a use of `a'
Possible fix:
add an instance declaration for (Data.Monoid.Monoid Char)
In the second argument of `(^.)', namely `a'
In the expression: (A 'a') ^. a
In an equation for `test2': test2 = (A 'a') ^. a
I could just go with _a, but the datatype in my real program is much deeper and I kind of intended on using lens to lower the amount of work I have to do. I have been looking over the lens library but there's so much there, and I'm not sure if he's dealt with this scenario or it is just something the lens library doesn't support.
As a side note, if I actually use a monoid like String for the datatype instead of Char, it then compiles and gives the right answer, I have no idea why.
Edit: After reading hammar's comment, I tried this and this works:
test2 = (A 'a') ^? a
test3 = B ^? a
But it is kind of weird to get a maybe out of that for something that has to exist.
Just so that this is answered, my problem was that I had an algebraic type where some fields were in common between the different constructors but there was a couple fields that weren't shared would die in runtime if I tried to use them.
data Exercise =
BarbellExercise {
name :: String,
weight :: Int,
reps :: Int
} |
BodyWeightExercise {
name :: String,
reps :: Int
}
exer1 = BarbellExercise "Squats" 235 15
exer2 = BarbellExercise "Deadlifts" 265 15
exer3 = BodyWeightExercise "Pullups" 12
exer4 = BarbellExercise "Overhead Press" 85 15
workout = [exer1, exer2, exer3, exer4]
test = do
mapM_ displayExercise workout
where
displayExercise x = putStrLn $ "Exercise: " ++ (name x) ++ " You must perform " ++ (show $ reps x) ++ "#" ++ (show $ weight x)
This compiles but dies runtime if I make the mistake of using the weight function. Understandable mistake. When lenses uses template haskell to generate instances it notices this and changes its behavior to prevent a mistake. You could remove the field accessors but in my case most of the fields were the same between datatypes. Here's how I should have written the data type once I noticed the fields did not match up:
data Exercise =
BarbellExercise
String -- ^ name
Int -- ^ reps
Int -- ^ weight
|
BodyWeightExercise
String -- ^ name
Int -- reps
name :: Exercise -> String
name (BarbellExercise n _ _) = n
name (BodyWeightExercise n _) = n
reps :: Exercise -> Int
reps (BarbellExercise _ r _) = r
reps (BodyWeightExercise _ r) = r
By doing it this way, while it is a little less clean, the error are caught at compile time. By forcing me to write the functions myself I would notice any partial functions as I was writing them.
I do kind of wish ghc would have warned me. It seems like it would be really easy for it to detect such a thing.

Create a type that can contain an int and a string in either order

I'm following this introduction to Haskell, and this particular place (user defined types 2.2) I'm finding particularly obscure. To the point, I don't even understand what part of it is code, and what part is the thoughts of the author. (What is Pt - it is never defined anywhere?). Needless to say, I can't execute / compile it.
As an example that would make it easier for me to understand, I wanted to define a type, which is a pair of an Integer and a String, or a String and an Integer, but nothing else.
The theoretical function that would use it would look like so:
combine :: StringIntPair -> String
combine a b = (show a) ++ b
combine a b = a ++ (show b)
If you need a working code, that does the same, here's CL code for doing it:
(defgeneric combine (a b)
(:documentation "Combines strings and integers"))
(defmethod combine ((a string) (b integer))
(concatenate 'string a (write-to-string b)))
(defmethod combine ((a integer) (b string))
(concatenate 'string (write-to-string a) b))
(combine 100 "500")
Here's one way to define the datatype:
data StringIntPair = StringInt String Int |
IntString Int String
deriving (Show, Eq, Ord)
Note that I've defined two constructors for type StringIntPair, and they are StringInt and IntString.
Now in the definition of combine:
combine :: StringIntPair -> String
combine (StringInt s i) = s ++ (show i)
combine (IntString i s) = (show i) ++ s
I'm using pattern matching to match the constructors and select the correct behavior.
Here are some examples of usage:
*Main> let y = StringInt "abc" 123
*Main> let z = IntString 789 "a string"
*Main> combine y
"abc123"
*Main> combine z
"789a string"
*Main> :t y
y :: StringIntPair
*Main> :t z
z :: StringIntPair
A few things to note about the examples:
StringIntPair is a type; doing :t <expression> in the interpreter shows the type of an expression
StringInt and IntString are constructors of the same type
the vertical bar (|) separates constructors
a well-written function should match each constructor of its argument's types; that's why I've written combine with two patterns, one for each constructor
data StringIntPair = StringInt String Int
| IntString Int String
combine :: StringIntPair -> String
combine (StringInt s i) = s ++ (show i)
combine (IntString i s) = (show i) ++ s
So it can be used like that:
> combine $ StringInt "asdf" 3
"asdf3"
> combine $ IntString 4 "fasdf"
"4fasdf"
Since Haskell is strongly typed, you always know what type a variable has. Additionally, you will never know more. For instance, consider the function length that calculates the length of a list. It has the type:
length :: [a] -> Int
That is, it takes a list of arbitrary a (although all elements have the same type) and returns and Int. The function may never look inside one of the lists node and inspect what is stored in there, since it hasn't and can't get any informations about what type that stuff stored has. This makes Haskell pretty efficient, since, as opposed to typical OOP languages such as Java, no type information has to be stored at runtime.
To make it possible to have different types of variables in one parameter, one can use an Algebraic Data Type (ADT). One, that stores either a String and an Int or an Int and a String can be defined as:
data StringIntPair = StringInt String Int
| IntString Int String
You can find out about which of the two is taken by pattern matching on the parameter. (Notice that you have only one, since both the string and the in are encapsulated in an ADT):
combine :: StringIntPair -> String
combine (StringInt str int) = str ++ show int
combine (IntString int str) = show int ++ str

How to override Show instance of some basic types in Haskell?

I'm writting some programs in Haskell, dealing with a lot of basic types like Word32/Word64 etc..
I use ghci to test the functions frequently, see the results in terminal.
To be convenient and fast, I always show data in hexadecimal e.g.
data Human = M Int | F Int
instance Show Human where
show M x = printf "man, age %d" x
show F x = printf "woman, age %d" x
but I want basic types to be showed in hexadecimal (espacially in ghci).
I found instance declaration cannot be overridden.
and I don't want to warp all of them up like:
newtype MyInt = MyInt Int
instance Show MyInt where
...
It looks a little bit stupid.
Can I modify some code in the package base for ghc?
I just want everything becoming "hex". I just want ghci showing "hex". how could I achieve it?
EDIT
Since all of us agree that override Show is not proper and impractical,
Any answer of "better ways to show Numeric in hexadecimal in ghci" is welcomed.
No, there is no way to achieve this without newtypes; instances cannot be overriden.
If you really want this, I would suggest defining your own typeclass, ShowHex, like Show but with all the instances printing in hex. However, I would consider your Show instance incorrect; Show instances are designed for debugging and serialisation, and should output syntactically valid code.1 Yours doesn't, so I would suggest either defining your own typeclass for displaying these values, or simply using a function.
Modifying the code to base for this is impractical; not only would this change in semantics for the instances break a lot of packages, but it'd be a huge pain to get GHC to actually use your modified version.
1 Ideally, the code they produce should be semantically valid Haskell that produces a value comparing equal to show's input, but this is not strictly necessary.
That would be abusing the Show instance. It's not really meant for formatting. If you want to show something in hexadecimal, just use a function to do the conversion. For example, you can use showHex from Numeric to make a small helper like this:
> import Numeric
Numeric> let hex x = showHex x ""
Numeric> hex 123456
"1e240"
One extreme solution would be to use {-# LANGUAGE NoImplicitPrelude #-}, and import your own "Prelude" instead. That would probably be a lot more work than it's worth for your case, though.
Agreeing with #ehird and #hammar that this could be abused. In the case of wanting some numbers to always show as hex, I think it's reasonable because "0xff" is a legitimate representation of a number. So this:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module HexNumber where
import Numeric
import Text.Read
import qualified Text.Read.Lex as L
newtype HexInt a = HexInt { int :: a }
deriving (Eq, Ord, Num, Enum)
instance (Show a, Integral a) => Show (HexInt a) where
show hi = "0x" ++ showHex (int hi) ""
instance (Num a) => Read (HexInt a) where
-- Couldn't figure out how to write this instance so just copy/paste from Text.Read
readPrec = readNumber convertInt
readListPrec = readListPrecDefault
readList = readListDefault
readNumber :: Num a => (L.Lexeme -> ReadPrec a) -> ReadPrec a
readNumber convert =
parens
( do x <- lexP
case x of
L.Symbol "-" -> do y <- lexP
n <- convert y
return (negate n)
_ -> convert x
)
convertInt :: Num a => L.Lexeme -> ReadPrec a
convertInt (L.Number n)
| Just i <- L.numberToInteger n = return (fromInteger i)
convertInt _ = pfail
Now I can:
> let x = 10 :: HexInt Int
> x
0xa
> x * 2
0x14
> let x = 10 :: HexInt Integer
> x
0xa
> x * 2
0x14
> read "0xa" :: HexInt Int
0xa
> read "10" :: HexInt Int
0xa
This seems very useful to me working with low-level stuff a lot. Maybe I'll put it on Hackage.

Resources