OCaml Double Semicolon Error in Toplevel - syntax-error

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 *)

Related

Changing a mutable field in OCaml

When I run the following code I get a syntax error, although as far as I can tell the syntax is correct. This attempts to implement a queue structure, where the function from_list converts a list to a queue with the corresponding values. I wrote str_of_int_q to print the contents of a queue. x and y are supposed to be two nodes, with x at the head and y at the tail.
;; open Assert
type 'a qnode = {v: 'a;
mutable next: 'a qnode option}
type 'a queue = {mutable head: 'a qnode option;
mutable tail: 'a qnode option}
let from_list (l: 'a list) : 'a queue =
let rec loop (l2: 'a list) (qu: 'a queue) =
begin match l2 with
| [] -> qu
| [x] -> let y = {v = x; next = None} in
qu.head <- Some y; qu.tail <- Some y;
qu
| h1::h2::t -> let y = qu.head in
let z = {v = h1; next = y} in
qu.head <- Some z;
qu
end
in loop l {head = None; tail = None}
let str_of_int_q (q: int queue) : string =
let rec loop (r: int qnode option) (s: string) : string =
begin match r with
| None -> s
| Some n -> loop n.next (s ^ (string_of_int n.v))
end
in loop q.head ""
let x = {v = 1; next = None}
let y = {v = 2; next = None}
x.next <- Some y;
let z = {head = Some x; tail = Some y}
;; print_endline (str_of_int_q z)
My error:
line 32, characters 7-9:
Error: Syntax error
Line 32 is the line x.next <- Some y; and characters 7-9 indicate the <-. But I'm storing into a mutable field an object of the appropriate type, so I don't see what's going wrong.
Top-level statements are separated by ;; in OCaml. However, ;; is optional before several keywords, such as let, open, type, etc. This is why you don't need ;; most of the time.
In your case, ;; is needed to disambiguate between let y = {v = 2; next = None} and x.next <- Some y. The latter is an expression and doesn't start with a special keyword, so OCaml doesn't know to insert an implicit ;; here.
See also http://ocaml.org/learn/tutorials/structure_of_ocaml_programs.html#The-disappearance-of.
As explained there, you can either do
let y = {v = 2; next = None}
;; x.next <- Some y
or
let y = {v = 2; next = None}
let () = x.next <- Some y
This latter solution works because by introducing a dummy binding we're starting our statement with let, which disambiguates again.
Note: I've also removed the trailing ; from your code. ; is actually an infix operator that combines two expressions (by throwing the result of the first one away and returning the result of the second one). This is not what you want here.

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

Binary operator '+=' cannot be applied to operands of type 'Int' and 'UInt8'

Translating Obj-C to Swift. As you can see I declared let buf = UnsafeMutablePointer<UInt8>(CVPixelBufferGetBaseAddress(cvimgRef)) so I'm getting the error in the for loop below it.
Binary operator '+=' cannot be applied to operands of type 'Int' and 'UInt8'
Also as a little addendum I don't know how to translate the remaining Obj-C code below the for loop. What does that slash mean and how do I deal with the pointer? I have to say UnsafeMutableFloat somewhere?
// process the frame of video
func captureOutput(captureOutput:AVCaptureOutput, didOutputSampleBuffer sampleBuffer:CMSampleBuffer, fromConnection connection:AVCaptureConnection) {
// if we're paused don't do anything
if currentState == CurrentState.statePaused {
// reset our frame counter
self.validFrameCounter = 0
return
}
// this is the image buffer
var cvimgRef:CVImageBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer)
// Lock the image buffer
CVPixelBufferLockBaseAddress(cvimgRef, 0)
// access the data
var width: size_t = CVPixelBufferGetWidth(cvimgRef)
var height:size_t = CVPixelBufferGetHeight(cvimgRef)
// get the raw image bytes
let buf = UnsafeMutablePointer<UInt8>(CVPixelBufferGetBaseAddress(cvimgRef))
var bprow: size_t = CVPixelBufferGetBytesPerRow(cvimgRef)
var r = 0
var g = 0
var b = 0
for var y = 0; y < height; y++ {
for var x = 0; x < width * 4; x += 4 {
b += buf[x]; g += buf[x + 1]; r += buf[x + 2] // error
}
buf += bprow() // error
}
Remaining Obj-C code.
r/=255*(float) (width*height);
g/=255*(float) (width*height);
b/=255*(float) (width*height);
You have a lot of type mismatch error.
The type of x should not be UInt8 because x to increase until the value of the width.
for var x:UInt8 = 0; x < width * 4; x += 4 { // error: '<' cannot be applied to operands of type 'UInt8' and 'Int'
So fix it like below:
for var x = 0; x < width * 4; x += 4 {
To increment the pointer address, you can use advancedBy() function.
buf += bprow(UnsafeMutablePointer(UInt8)) // error: '+=' cannot be applied to operands of type 'UnsafeMutablePointer<UInt8>' and 'size_t'
Like below:
var pixel = buf.advancedBy(y * bprow)
And this line,
RGBtoHSV(r, g, b) // error
There are no implicit casts in Swift between CGFloat and Float unfortunately. So you should cast explicitly to CGFloat.
RGBtoHSV(CGFloat(r), g: CGFloat(g), b: CGFloat(b))
The whole edited code is here:
func RGBtoHSV(r: CGFloat, g: CGFloat, b: CGFloat) -> (h: CGFloat, s: CGFloat, v: CGFloat) {
var h: CGFloat = 0.0
var s: CGFloat = 0.0
var v: CGFloat = 0.0
let col = UIColor(red: r, green: g, blue: b, alpha: 1.0)
col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
return (h, s, v)
}
// process the frame of video
func captureOutput(captureOutput:AVCaptureOutput, didOutputSampleBuffer sampleBuffer:CMSampleBuffer, fromConnection connection:AVCaptureConnection) {
// if we're paused don't do anything
if currentState == CurrentState.statePaused {
// reset our frame counter
self.validFrameCounter = 0
return
}
// this is the image buffer
var cvimgRef = CMSampleBufferGetImageBuffer(sampleBuffer)
// Lock the image buffer
CVPixelBufferLockBaseAddress(cvimgRef, 0)
// access the data
var width = CVPixelBufferGetWidth(cvimgRef)
var height = CVPixelBufferGetHeight(cvimgRef)
// get the raw image bytes
let buf = UnsafeMutablePointer<UInt8>(CVPixelBufferGetBaseAddress(cvimgRef))
var bprow = CVPixelBufferGetBytesPerRow(cvimgRef)
var r: Float = 0.0
var g: Float = 0.0
var b: Float = 0.0
for var y = 0; y < height; y++ {
var pixel = buf.advancedBy(y * bprow)
for var x = 0; x < width * 4; x += 4 { // error: '<' cannot be applied to operands of type 'UInt8' and 'Int'
b += Float(pixel[x])
g += Float(pixel[x + 1])
r += Float(pixel[x + 2])
}
}
r /= 255 * Float(width * height)
g /= 255 * Float(width * height)
b /= 255 * Float(width * height)
//}
// convert from rgb to hsv colourspace
var h: Float = 0.0
var s: Float = 0.0
var v: Float = 0.0
RGBtoHSV(CGFloat(r), g: CGFloat(g), b: CGFloat(b)) // error
}

Translating Obj-C RGBtoHSV() function to Swift. min = MIN( r, MIN(g, b )); etc

Could someone please help me with this function? This function is inside of a camera app that uses a filter algorithm to detect differences in colour variants etc. The syntax is very difficult for me. I don't know how to deal with the pointers in the arguments, the min and max variable syntax, what is delta etc? Could someone please translate for me? Much appreciated.
Also should I be doing something with UIColor? Someone mentioned it below. I have no idea how to convert though.
// r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1]
// if s == 0, then h = -1 (undefined)
void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v ) {
float min, max, delta;
min = MIN( r, MIN(g, b ));
max = MAX( r, MAX(g, b ));
*v = max;
delta = max - min;
if( max != 0 )
*s = delta / max;
else {
// r = g = b = 0
*s = 0;
*h = -1;
return;
}
if( r == max )
*h = ( g - b ) / delta;
else if( g == max )
*h=2+(b-r)/delta;
else
*h=4+(r-g)/delta;
*h *= 60;
if( *h < 0 )
*h += 360;
}
Swift translation attempt
// r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1]
// if s == 0, then h = -1 (undefined)
func RGBtoHSV(r:Float, g:Float, b:Float, h:Float, s:Float, v:Float) {
var min:Float = 0.0
var max:Float = 0.0
var delta:Float = 0.0
min = MIN(r, MIN(g, b))
max = MAX(r, MAX(g, b))
var v = max
delta = max - min
if max != 0 {
var s = delta / max
}
else{
// r = g = b = 0
var s = 0
var h = -1
return
}
if r == max {
var h = (g - b) / delta
}
else if (g == max) {
var h = 2 + (b - r ) / delta
}
else{
var h = 4 + (r - g) / delta
var h = 60
}
if (h < 0) {
var h += 360 // how to deal with all of these pointers here in the original Obj-C function above?
}
}
The Swift equivalent of passing a pointer (the address of a variable)
is an "inout parameter":
func RGBtoHSV(r : Float, g : Float, b : Float, inout h : Float, inout s : Float, inout v : Float) {
let rgbMin = min(r, g, b)
let rgbMax = max(r, g, b)
let delta = rgbMax - rgbMin
v = rgbMax
s = delta/rgbMax
h = Float(0.0) // Replace by your actual calculation
}
This would be called as
let r : Float = 0.3
let g : Float = 0.5
let b : Float = 0.7
var h : Float = 0.0
var s : Float = 0.0
var v : Float = 0.0
RGBtoHSV(r, g, b, &h, &s, &v)
println([h, s, v])
But in Swift there is a better way to return multiple values:
You can return a tuple:
func RGBtoHSV(r : Float, g : Float, b : Float) -> (h : Float, s : Float, v : Float) {
let rgbMin = min(r, g, b)
let rgbMax = max(r, g, b)
let delta = rgbMax - rgbMin
let v = rgbMax
let s = delta/rgbMax
let h = Float(0.0) // Replace by your actual calculation
return (h, s, v)
}
And this would be called as
let r : Float = 0.3
let g : Float = 0.5
let b : Float = 0.7
let (h, s, v) = RGBtoHSV(r, g, b)
println([h, s, v])
Note that on iOS you can simply use the UIColor class to convert
between RGB and HSV (== HSB):
func RGBtoHSV(r : CGFloat, g : CGFloat, b : CGFloat) -> (h : CGFloat, s : CGFloat, v : CGFloat) {
var h : CGFloat = 0.0
var s : CGFloat = 0.0
var v : CGFloat = 0.0
let col = UIColor(red: r, green: g, blue: b, alpha: 1.0)
col.getHue(&h, saturation: &s, brightness: &v, alpha: nil)
return (h, s, v)
}
(or use the various extension/convenience methods from
What is the best/shortest way to convert a UIColor to hex (web color) in Swift?)

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

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