How do I define a recursive struct in Racket? - struct

I'm trying to imitate recursive types in OCaml in untyped Racket, but I can't seem to find documentation on defining recursive structs. How would I go about mapping this:
type example =
| Red
| Blue of example
| Yellow of example * example;;
into something in Racket?
I've tried the following:
(struct Red ())
(struct Blue (e1))
(struct Yellow (e1 e2))
(struct example/c
(or/c (Red)
(Blue example/c)
(Yellow example/c example/c)))
However, it doesn't work as expected when I put example/c in a contract, because it claims it's a procedure. Any help?

I have changed the example.
Here is an example where the variable e has the contract example/c.
#lang racket
(struct Red () #:transparent)
(struct Blue (e1) #:transparent)
(struct Yellow (e1 e2) #:transparent)
(define example/c
(flat-murec-contract ([red/c (struct/c Red)]
[blue/c (struct/c Blue example/c)]
[yellow/c (struct/c Yellow example/c example/c)]
[example/c (or/c red/c blue/c yellow/c)])
example/c))
(define r (Red))
(define b (Blue r))
(define y (Yellow r b))
(define e y)
(provide (contract-out [e example/c]))
(match e
[(Red) (list "Red")]
[(Blue e1) (list "Blue" e1)]
[(Yellow e1 e2) (list "Yellow" e1 e2)]
[else "huh"])
If you change, say, (Yellow r b) to (Yellow r 42) then you get an error.

Related

Pattern matching in Racket

I have this code snippet in Haskell:
matchEx :: Expr -> [Expr]
matchEx (Number n) = undefined
matchEx (Boolean b) = undefined
matchEx (If condStatement thenStatement elseStatement) = undefined
What would the equivalent pattern matching looks like in racket? After looking at the documentation, this is what I have. Thanks.
(define (matchEx-calls expr)
(match expr
[(literal n) ([])]
[(id ident) ([])]
[(If condStatement thenStatement elseStatement) ([])]
)
)
Here is an example to get you started:
#lang racket
(struct Expr () #:transparent)
(struct Number Expr (n) #:transparent)
(struct Boolean Expr (b) #:transparent)
(struct Or Expr (exprs) #:transparent)
(define (format-Expr e)
(define ~ format-Expr)
(match e
[(Number n) (~a n)]
[(Boolean b) (if b "true" "false")]
[(Or es) (match es
['() "true"]
[(list e) (~ e)]
[(list e1 e2) (~a (~ e1) " or " (~ e2))]
[(list e1 es ...) (~a (~ e1) " or " (~ (Or es)))])]
[(? Expr? e)
; we get here if we forgot to implement a case
(error 'format-expr (~a "internal error, got: " e))]
[_
; this on the other hand is an user error
(error 'format-expr (~a "expected an Expr, got: " e))]))
(format-Expr (Or (list (Boolean #t) (Boolean #f))))

Error with values in structs

I have started to build a small game in racket using the 2htdp/universe library. My code so far:
#lang racket
(require 2htdp/image 2htdp/universe)
(define BIRD-IMG (scale .2 (object:image% ...)) ; Image URL: http://i.stack.imgur.com/Vz26B.png
(struct world (bird) #:transparent)
(struct pos (x y) #:transparent)
(struct bird (pos img) #:transparent)
(define-values (WIDTH HEIGHT)
(values 600 600))
(define DEFAULT-STATE (world (bird (pos (/ WIDTH 2) (/ HEIGHT 2)) BIRD-IMG)))
(define (move-bird w x y dir)
(world
(bird
(pos
(let
([new-x (+ (pos-x (bird-pos (world-bird w))) x)]
[new-y (+ (pos-y (bird-pos (world-bird w))) y)])
(values
(cond
[(> new-x WIDTH) WIDTH]
[(< new-x 0) 0]
[else new-x])
(cond
[(> new-y HEIGHT) HEIGHT]
[(< new-y 0) 0]
[else new-y]))))
(case dir
[("up") BIRD-IMG]
[("down") (rotate 180 BIRD-IMG)]
[("left") (rotate 90 BIRD-IMG)]
[("right") (rotate -90 BIRD-IMG)]
[else (bird-img (world-bird w))]))))
(define (render w)
(place-image (bird-img (world-bird w))
(pos-x (bird-pos (world-bird w)))
(pos-y (bird-pos (world-bird w)))
(empty-scene WIDTH HEIGHT)))
(define (handle-keys w key)
(case key
[("up") (move-bird w 0 -5 key)]
[("down") (move-bird w 0 5 key)]
[("left") (move-bird w -5 0 key)]
[("right") (move-bird w 5 0 key)]
[else w]))
(big-bang DEFAULT-STATE
(on-draw render)
(on-key handle-keys)
(on-tick (lambda (w) w) 20)
(name "Bird Simulator 2016"))
My problem: When I try to press the arrow keys to move the bird in a direction, there is an error in the 'move-bird' function:
result arity mismatch;
expected number of values not received
expected: 1
received: 2
values...:
Running it through DrRacket's debugger, I can see that it is where the variables from the let have gone out of scope, but the program is at a lower level than the outermost world struct. I am confused because the arity mismatch error didn't name any particular place/function, and I certainly don't see any place where more values are given then are required. The world struct is passed only a bird struct, and the bird struct only a pos and an img. It might have to do with the let inside of the pos struct, but I am not sure. Please help!

RGB to CMYK in Haskell

I'm suppposed to convert a given RGB color to CMYK format, and in case of white (0,0,0) I should get (0,0,0,1). I've been trying this whole night but every time it crashes, could please someone tell what's wrong?
rgb2cmyk :: (Int,Int,Int) -> (Float,Float,Float,Float)
rgb2cmyk (r,g,b) = (c,m,y,k)
| (r,g,b) == (0,0,0) = (0,0,0,1)
| otherwise = ((w - (r/255))/w, (w - (g/255))/w, (w - (b/255))/w, 1 - w)
where
w = maximum [r/255, g/255, b/255]
I get: parse error on input '|'
You want to say either
rgb2cmyk (r, g, b) = ...
or
rgb2cymk (r, g, b)
| ... = ...
| ... = ...
But not both at the same time. (Which expression would it execute?)
As an aside, you don't actually need to test (r,g,b) == (0,0,0); you can just pattern-match (0,0,0) directly.
rgb2cymk (0,0,0) = (0,0,0,1)
rgb2cymk (r,g,b) = ???
The section = (c, m, y, k) in rgb2cmyk (r,g,b) = (c,m,y,k) is incorrect.
When using guards, you should think of it as using something like
rgb2cmyk (r,g,b) = case (r,g,b) of
(0,0,0) -> (0,0,0,1)
_ -> ...
as this is what GHC will actually rewrite your guards into (this is the same with if, as well, which turns into case predicate of...).
It doesn't make sense to write
rgb2cmyk (r,g,b) = (c,m,y,k)
And then later on have:
case (r,g,b) of ...
sitting as a floating definition in your source file.

Wrong output of simple Haskell exercise solution

I am trying to solve this exercise:
You are given a sequence of N balls in 4 colors: red, green, yellow
and blue. The sequence is full of colors if and only if all of the
following conditions are true:
There are as many red balls as green balls.
There are as many yellow balls as blue balls.
Difference between the number of red balls and green balls in every prefix of the sequence is at most 1.
Difference between the number of yellow balls and blue balls in every prefix of the sequence is at most 1.
Your task is to write a program, which for a given sequence prints True if it is full of colors, otherwise it prints False.
My solution so far is:
module Main where
import Control.Monad
main = do
s <- readLn :: IO Int
elements <- replicateM s getLine
let result = map checkColours elements
mapM (putStrLn . show) result
checkColours :: String -> Bool
checkColours string = isFullOfColors 0 0 0 0 string
isFullOfColors :: Int -> Int -> Int -> Int -> String -> Bool
isFullOfColors red green yellow blue string
| (abs (red - green)) > 1 = False
| (abs (yellow - blue)) > 1 = False
| (string == []) = if (red /= yellow) || (green /= blue) then True else False
| (head string == 'R' ) = isFullOfColors (red + 1) green yellow blue (tail string)
| (head string == 'G' ) = isFullOfColors red (green + 1) yellow blue (tail string)
| (head string == 'Y' ) = isFullOfColors red green (yellow + 1) blue (tail string)
| (head string == 'B' ) = isFullOfColors red green yellow (blue + 1) (tail string)
But it fails on the input "RYBG", returning False instead of True.
What am I doing wrong?
Besides C. Quilley's comments, here is some general advice and a suggestion for structuring your function differently. The guard string == [] is better written as null string, since the built-in function null will make this decision with a single pattern match, rather than having to rely on the list of elements being comparable (which it only is when the elements of the list themselves are comparable). The pattern if ... then True else False can be shortened to ..., since this is already a boolean with the same value. Generally, try and use pattern matching!
I cannot see where you derive (red /= yellow) || (green /= blue) from. When does the number of red balls and yellow balls have constraints in common?
Instead of a String, you may want to create a data type that reflects balls:
data Ball = Red | Green | Yellow | Blue
deriving Eq
You may want them to be displayed just the same as before:
instance Show Ball where
show Red = "R"
show Green = "G"
show Yellow = "Y"
show Blue = "B"
And you may want to embed the helper function inside the main function:
isFullOfColors :: [Ball] -> Bool
isFullOfColors = go (0, 0, 0, 0)
where
go :: (Int, Int, Int, Int) -> [Ball] -> Bool
go (r,g,y,b) (Red:balls) = ...
go (r,g,y,b) (Green:balls) = ...
go (r,g,y,b) (Yellow:balls) = ...
go (r,g,y,b) (Blue:balls) = ...
go (r,g,y,b) [] = ...
As for hints on the logical part: These can be expressed as comparisons between r, g, y and b in combination with recursive calls to balls.

String representation of custom data in Racket

I like how you can retain representation in transparent structs:
(struct posn (x y)
#:transparent)
> (posn 1 2)
(posn 1 2)
But is there a way to customize it? Like in Python?
Check out the prop:custom-write property here. Here's a simple implementation:
(struct pr (x y)
#:transparent
#:property prop:custom-write (λ (v p w?)
(fprintf p "<~a,~a>" (pr-x v) (pr-y v))))
> (pr 1 2)
<1,2>
Note that this works with non-#:transparent structures as well.

Resources