Printing new types in Haskell - haskell

I'm following a tutorial to create a new type. This is my code:
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
When I load the file with ghci and I type:
Circle 10 20 5
It prints this:
<interactive>:29:1:
No instance for (Show Shape) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it
How can I solve this?

The show function has type:
show :: Show a => a -> String
Which means it only works on things with a Show instances. You can make your types an instance of the Show class by either manually defining an instance or letting the compiler automatically derive one:
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
deriving (Show)
or
instance Show Shape where
show (Circle a b c) = "Circle " ++ show a ++ " " ++ show b ++ " " ++ show c
show (Rectangle a b c d) = ...

I solved it typing this in the interpreter:
:s -u

Related

Can't define function on user-defined data-type

I'm following a tutorial and have the following type definitions:
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
Loading the file with these definitions into ghci, and wanting to define a function, using
surface :: Shape -> Float
I get the error message Variable not in scope: surface :: Shape -> Float.
I don't even see where I do have a variable, let alone why I get this error! Any help highly appreciated.
GHCi finds the type signature for surface but can't parse the file because there's no body for that function. In Haskell functions cannot be declared but undefined.
If you still need to load your file you can add surface = undefined
data Point = Point Float Float deriving (Show)
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
surface :: Shape -> Float
surface = undefined
Use multiline input in ghci
Prelude> :{
Prelude| surface :: Shape -> Float
Prelude| surface = undefined
Prelude| :}

Haskell Data Declarations

Codes below are from Programming in Haskell by Hutton (p.101).
data Shape = Circle Float | Rect Float Float
square :: Float -> Shape
square n = Rect n n
area : Shape -> Float
area(Rect x y) = x * y
In ghci, if I type area(Rect 3 5), I get 15.
But if I type square 5(thinking that I would get Rect 5 5 as a result), I get an error message:
"No instance for (Show Shape) arising from a use of ‘print’
In a stmt of an interactive GHCi command: print it".
Why is that?
Behind the scenes, GHCi is trying to call print (square 5). Unfortunately this requires Shape to implement something called the Show typeclass. You can make the error go away by adding deriving Show to the end of the data Shape = Circle Float | Rect Float Float deriving Show.
There's a great section on the Show typeclass in Learn You a Haskell and a great answer on deriving in Stack Overflow.

Instance of Show Haskell

I am doing my homework and I have a problem doing an instance of Show and I can't solve it, I tried a lot of things. I copy you the error and my code below.
My code:
type Height = Float
type Width = Float
type Radius = Float
data Rectangle = Rectangle Height Width
data Circle = Circle Radius
class Shape a where
area :: a -> Float
perimeter :: a -> Float
instance Shape Rectangle where
area (Rectangle h w) = h * w
perimeter (Rectangle b a) = (2*b) + (2*a)
instance Shape Circle where
area (Circle r) = pi * r**2
perimeter (Circle r) = 2*r*pi
type Volume = Float
volumePrism :: (Shape a) => a -> Height -> Volume
volumePrism base height = (area base) * height
surfacePrism ancho largo alto = (2*ancho*largo) + (2*largo*alto) + (2*ancho*alto)
instance Show a => Show (Shape a) where
show (Rectangle h w) = "Rectángulo de base " ++ w ++ "y altura " ++ h
And what the error says:
The first argument of 'Show' should have kind '*'
What you want to do is not possible. Shape is a typeclass, not a data type, so it has no constructors you can pattern match on. You could do something like
instance (Shape a) => Show a where
show shape = "Area: " ++ show (area shape) ++ " Perimeter: " ++ show (perimeter shape)
But this does not seem to be what you want. Instead, you should just define Show for each type individually:
instance Show Rectangle where
show (Rectangle h w) = "Rectangle with base " ++ show w ++ " and height " ++ show h
instance Show Circle where
show (Circle r) = "Circle with radius " ++ show r
The error about the "kind" can be quite cryptic for beginners (and sometimes experienced haskellers!), but in this case it's fairly straightforward. This does involve a new concept, though. In Haskell, you have values which have a type, such as functions, constants, even monadic actions. You can also talk about the "type of a type", what is known as the kind. There are a couple that you should know about and be comfortable using: * and Constraint. Most types you'll see only involve * and arrows between them. All "fully applied" data types should have kind *, it basically just means that it doesn't take any type parameters, so
> :kind Int
Int :: *
> :kind String
String :: *
> :kind IO ()
IO () :: *
> :kind Maybe Int
Maybe Int :: *
> :kind Either String Int
Either String Int :: *
However, you can have higher-kinded types as well:
> :kind IO -- Note lack of ()
IO :: * -> *
> :kind Maybe
Maybe :: * -> *
> :kind Either
Either :: * -> * -> *
Each * just represents another fully applied type. That last detail is important, it means you can't have Either IO Maybe, because that would be a nonsensical type. These can be higher order as well:
> import Control.Monad.State
> :kind StateT
StateT :: * -> (* -> *) -> * -> *
It's the same syntax as with function types, just without kind variables.
The other one you really need to know about is Constraint. This one is specially for typeclasses:
> :kind Show
Show :: * -> Constraint
> :kind Num
Num :: * -> Constraint
> :kind MonadState
MonadState :: * -> (* -> *) -> Constraint
And when fully applied they return a typeclass, rather than a datatype.
In case you're curious, there are GHC extensions that let you work with more complicated kinds, even allowing you to specify the kinds for a type or typeclass. There are some interesting tricks you can do with it, but these are generally considered more advanced features of the type system.
Shape is a typeclass, and you can’t make a typeclass an instance of another typeclass. (You can make all types that are an instance of a typeclass an instance of a different typeclass as well, but that doesn’t appear to be what you’re trying to do here.)
Rather, you appear to want to implement Show on Rectangle. So say that explicitly:
instance Show Rectangle where
show (Rectangle h w) = "Rectángulo de base " ++ w ++ "y altura " ++ h
Your instance declaration is not meaningful. Translated to English it would read as something like "for every a that is an instance of Show, a being an instance of Shape is an instance of Show" or something incomprehensible like that.
Just make Rectangle and Circle instances of Show and leave Shape out of it, unless you want to require that every instance of Shape must be an instance of Show, which is something that you need to put into the declaration of Shape.

Haskell -- Instance constraints bindings

I am learning Haskell programming language to understand functional programming paradigm.
I was trying to write following code
class Area shape where
area :: (Num n) => shape n -> n
data Quadrilateral t = Rectangle {length::t, width::t} | Square {side::t} deriving(Show)
data CircularShape t = Circle {radius::t} deriving(Show)
instance Area Quadrilateral where
area (Rectangle l w) = l * w
area (Square s ) = s * s
instance Area CircularShape where
area (Circle r) = pi * r * r
main = do
putStrLn . show . area $ Rectangle 10.0 20.0
putStrLn . show . area $ Square 10
putStrLn . show . area $ Circle 10.0
Here is the link for code
I am getting error below,
Error occurred
ERROR line 13 - Cannot justify constraints in instance member binding
*** Expression : area
*** Type : (Area CircularShape, Num a) => CircularShape a -> a
*** Given context : (Area CircularShape, Num a)
*** Constraints : Floating a
I am not able to understand the exact cause of this error. This code was working fine before adding the CircularShape data and it's corresponding instance of Area typeclass.
How I can solve this if I want to use both Quadrilateral and CircularShape ?
Since we are using different compiler, I show you the output of my error window.
box.hs|14 col 23 error| Could not deduce (Floating n) arising from a use of ‘pi’
|| from the context (Num n)
|| bound by the type signature for
|| area :: Num n => CircularShape n -> n
|| at /Users/evan/box.hs:14:5-8
|| Possible fix:
|| add (Floating n) to the context of
|| the type signature for area :: Num n => CircularShape n -> n
|| In the first argument of ‘(*)’, namely ‘pi’
|| In the first argument of ‘(*)’, namely ‘pi * r’
|| In the expression: pi * r * r
Basically, in your typeclass declaration, n is bound into Num which is too generic if you want to multiply it with pi, which is a floating point type.
Try changing Num into Floating
class Area shape where
area :: (Floating n) => shape n -> n
You might get a warning of something like "Defaulting to Double" which is because there are two floating types in haskell, (i.e Float and Double)
Change the type signature of area to
area:: (Floating n) => shape n -> n
Your code didn't work because multiplication with pi requires the type constraint Floating a
Also use print instead of putStrLn . show

export from module

Here is a code taken from http://www.angelfire.com/tx4/cus/shapes/haskell98.html .
It compiles and executes correctly in WinGHCi if I comment the names in the module header. But if the names are kept then it does not compile - it reports an error on the name MakeCircle. My question is: if I want to explicitly mention that I want to export MakeCircle, what code changes are required?
module Circle -- (Circle, MakeCircle, getRadius, setRadius)
where
import Shape
class Shape a => Circle a where
getRadius :: a -> Int
setRadius :: a -> Int -> a
instance Shape CircleInstance where
getX = x
getY = y
setX a newx = a {x = newx}
setY a newy = a {y = newy}
moveTo a newx newy = a {x = newx, y = newy}
rMoveTo a deltax deltay = a {x = ((getX a) + deltax), y = ((getY a) + deltay)}
draw a =
putStrLn ("Drawing a Circle at:(" ++ (show (getX a)) ++ "," ++ (show (getY a)) ++
"), radius " ++ (show (getRadius a)))
instance Circle CircleInstance where
getRadius = radius
setRadius a newradius = a {radius = newradius}
data CircleInstance = MakeCircle {x, y, radius :: Int}
deriving(Eq, Show)
MakeCircle is a data constructor for the type CircleInstance. Data constructors can only be exported in combination with their defining type. You will probably also want to export the Circle class methods getRadius and setRadius; with the current export list those methods will be unavailable outside this module.
Change your export list to
module Circle (Circle (..), CircleInstance (MakeCircle), getRadius, setRadius)
This shows two forms of exporting. The export Circle (..) exports the type class Circle and all of its methods, while CircleInstance (MakeCircle) exports the type constructor CircleInstance and only its data constructor MakeCircle. If you were to add a new data constructor for MakeCircle, perhaps a UnitCircle, that constructor wouldn't be exported from the module unless you either mention it in the export list (i.e. CircleInstance (MakeCircle, UnitCircle) ) or use the (..) form of exports.
The export list is incorrect, it should be:
module Circle(Circle, CircleInstance(MakeCircle), getRadius, setRadius)
Or perhaps
module Circle(Circle, CircleInstance(..), getRadius, setRadius)

Resources