How do you create an instance of a datatype with a record in SML? - record

For example if you were to have
datatype 'a DT =
thingy of {field1: int, field2: int}
| Empty DT;
How would you be able to create "thingy" with its fields filled in, within a function? Assuming you have the values you want for each field.

- datatype 'a DT = thingy of {x: int, y: int} | Empty;
datatype 'a DT = Empty | thingy of {x:int, y:int}
- thingy {x = 5, y = 4};
val it = thingy {x=5,y=4} : 'a DT
- fun f x y = thingy {x = x, y = y};
val f = fn : int -> int -> 'a DT

Related

The instance variable super cannot be accessed from the definition of another instance variable

i'm trying to do some OOP in OCAML.
Here are two classes :
class virtual game_object id x y z =
object (self)
val id : int = id
val x : int = x
val y : int = y
val z : int = z
method get_x = x
method get_y = y
method get_z = z
end;;
class tile id x y z tile_type =
object(self)
inherit game_object id x y z as super
val tile_type : tile_type = tile_type
val w : int = 80
val h : int = 80
val box : Sdl.rect = Sdl.Rect.create super#get_x super#get_y w h (* This line triggers the error *)
method get_tile_type = tile_type
end
;;
When I try to compile, I get this error :
The instance variable super cannot be accessed from the definition of another instance variable
I have no idea how to solve this issue. Please help? Thank you.
The simplest solution might be to factorize the common part of the value instance, avoid the getter of the super class, and just define the rectangle from the class arguments:
class tile id x y z tile_type =
let w = 80 in
let h = 80 in
object(self)
val box = Sdl.Rect.create x y w h
inherit game_object id x y z as super
val tile_type : tile_type = tile_type
val w = w
val h = h
method get_tile_type = tile_type
end
If you need to access x and y through the getters, you could make rect mutable, initialize it to a dummy value first, and then add an initializer to set it to the correct value:
class tile id x y z tile_type =
object(self)
inherit game_object id x y z as super
val tile_type : tile_type = tile_type
val w = 80
val h = 80
val mutable box = Sdl.Rect.create 0 0 0 0
initializer box <- Sdl.Rect.create super#get_x super#get_y w h
method get_tile_type = tile_type
end

Avoiding explicit record typing

Suppose I have the following functions for operating over an idealized stream:
fun Stream s = { pos = 0, row = 1, col = 0, str = s }
fun len { str, pos = _, row = _, col = _ } = String.size str
fun poke off { str, pos, row: int, col: int } =
let val n = pos + off in
if n >= 0 andalso n <= (String.size str) then SOME (String.sub(str, n)) else NONE
end
This works/compiles, but it's unfortunate to have to litter my function definitions with information I don't care about. row/col are ignored poke and len. However, while the wildcard can be used with len, it can't be with poke. Is there a way to restructure these functions so that less explicit typing needs to be put in, while still being able to pattern match/destructure?
If you give your type a name (such as stream), you can refer to it more briefly:
type stream = { pos : int, row : int, col : int, str : string }
fun Stream s = { pos = 0, row = 1, col = 0, str = s }
fun len ({ str, ... } : stream) = String.size str
fun poke off ({ str, pos, ... } : stream) =
let val n = pos + off in
if n >= 0 andalso n <= String.size str
then SOME (String.sub (str, n))
else NONE
end
Or, more-or-less equivalently:
datatype stream = STREAM of { pos : int, row : int, col : int, str : string }
fun Stream s = STREAM { pos = 0, row = 1, col = 0, str = s }
fun len (STREAM { str, ... }) = String.size str
fun poke off (STREAM { str, pos, ... }) =
let val n = pos + off in
if n >= 0 andalso n <= String.size str
then SOME (String.sub (str, n))
else NONE
end

OCaml Double Semicolon Error in Toplevel

I am receiving this odd syntax error in the OCaml toplevel.
# #use "ex_8_4.ml";;
type blob = {
get : unit -> float * float;
area : unit -> float;
set : float * float -> unit;
move : float * float -> unit;
}
val new_rectangle : float -> float -> float -> float -> blob = <fun>
# let rect1 = new_rectangle 0.0 0.0 1.0 1.0 in
let rect2 = {rect1 with set = (fun _ -> ())};;
Error: Syntax error
The copying failed to include that the semicolons are underlined in the error.
It happens because the toplevel is expecting an in keyword instead of semicolons:
> let a = 1 in let b = 2;;
Error: Syntax error
One fix would be to add an in at the end:
> let a = 1 in let b = 2 in a + b;;
- : int = 3
But the simplest would be to end each let binding with semicolons:
> let a = 1;;
val a : int = 1
> let b = 2;;
val b : int = 2
> a + b;;
- : int = 3
IonuČ› G. Stan's answer is correct if what you want to define rect1 for future use, or if you don't mind that it's defined. If you wanted rect1 to be defined only for local use in defining rect2, you could use this method:
# type ints = {a : int; b : int};;
(* type ints = { a : int; b : int; } *)
# let y =
let x = {a = 1; b = 2} in
{x with b = 5};;
(* val y : ints = {a = 1; b = 5} *)
# x;;
(* Error: Unbound value x *)

F# HashCode to enum conversion

I have an enum of bit-masked error codes with a string representation and an binary int representation:
type ErrorCodes =
| NoError = 0
| InvalidInputError = 1
| AuthenticationFailedError = 2
| InvalidArgumentError = 4
| ItemNotFoundError = 8
| UnknownError = 16
As I run through the program, I collect all the errors by using the bitwise OR operator (|||). So now I have something that looks like 01100. How can I print to the console: "InvalidArgumentError", and "ItemNotFoundError?"
I had an idea of just using:
for i = 0 to 32 do
if ((err.GetHashCode() % 2) = 1) then
Console.WriteLine("ErrorCode: {0}",err.GetHashCode())
But now I'm stuck on how to print the actual string
If you decorate your ErrorCodes type with the System.Flags attribute then .ToString will format as a list of value names.
[<System.Flags>]
type ErrorCodes = ...
let errors = ErrorCodes.InvalidInputError ||| ErrorCodes.UnknownError
printfn "%O" errors
If, for whatever reason, you don't want the default flags ToString implementation, you could do something like this:
let inline printFlags (flags: 'e) =
let ty = typeof<'e>
(Enum.GetValues ty :?> 'e[], Enum.GetNames ty)
||> Array.zip
|> Seq.filter (fun (v, _) -> v <> enum 0 && flags &&& v = v)
|> Seq.iter (snd >> printfn "%s")
printFlags (ErrorCodes.InvalidInputError ||| ErrorCodes.UnknownError)
Output:
InvalidInputError
UnknownError

Elm drawing over list

I am trying to draw a list of objects but cannot get it to work.
Secondary question is how do I make a "for loop" using ELM.
I have a
type Object a = { a | x:Float, y:Float, vx:Float, vy:Float }
type Car = Object {}
type Cars = [Car]
displayCar = move (car.x,car.y) (filled white (rect 30 20))
displayCars = ?????
I am trying to get somethign liek this to work
collage 100 100 [displayCar (head cars) -- does work
, displayCars cars -- does not work
]
In particular, the collage has multiple things it needs to plot:
[ filled pongGreen (rect gameWidth gameHeight)
, displayObjHouse (game.houses !! 0) -- so ugly code
, displayObjHouse (game.houses !! 1) -- so ugly code
, displayObjHouse (game.houses !! 2) -- so ugly code
, displayObjHouse (game.houses !! 3) -- so ugly code
, displayObjHouse (game.houses !! 4) -- so ugly code
, displayCars cars -- does not work
]
You are looking for the function map.
map : (a -> b) -> [a] -> [b]
This means that you can apply some function to a list of things and get back a list of the results.
You are very close with what you have here. I've filled in some blanks to help you keep making progress! Good luck!
type Object a = { a | x:Float, y:Float, vx:Float, vy:Float }
type Car = Object {}
type House = Object { residents : Int }
displayCar : Car -> Form
displayCar car = move (car.x,car.y) (filled black (rect 30 20))
displayCars : [Car] -> [Form]
displayCars cars = map displayCar cars
-- map : (a -> b) -> [a] -> [b]
-- In our particular example, we plug in our functions
-- displayCar : Car -> Form
-- since display car is the first argument to map, all a's become Car
-- and all b's become Form
-- So the type of map in this instance is ((Car -> Form) -> [Car] -> [Form]
someCars : [Car]
someCars = [ { x = 100, y = 10, vx = 0, vy = 0 }
, { x = 35, y = 100, vx = 0, vy = 0 }
, { x = 0, y = 0, vx = 0, vy = 0 }
]
someHouses : [House]
someHouses = [ { x = 20, y = -100, vx = 0, vy = 0, residents = 3 }
, { x = -20, y = -50, vx = 0, vy = 0, residents = 3 }
, { x = 160, y = -150, vx = 0, vy = 0, residents = 3 }
]
displayHouse : House -> Form
displayHouse house = move (house.x, house.y) (filled blue (rect 30 50))
main : Element
main =
let houses = map displayHouse someHouses
cars = map displayCar someCars
in collage 400 400 (houses ++ cars)