Implementation of Array data type in OCaml - arrays

I have very little knowledge about OCaml as a whole and just received an assignment to take one of the source files in the project and allow it to take a new data type (Array). I am not asking for someone to solve this problem for me, but instead I would appreciate someone walking me through this code. I would also appreciate any input on how difficult it is going to be to implement this new data type.
The file itself lacks a lot of documentation which doesn't make it any easier either.
(* * Types (hashconsed) *)
(* ** Imports *)
open Abbrevs
open Util
(* ** Identifiers *)
module Lenvar : (module type of Id) = Id
module Tysym : (module type of Id) = Id
module Groupvar : (module type of Id) = Id
module Permvar : (module type of Id) = Id
(* ** Types and type nodes *)
type ty = {
ty_node : ty_node;
ty_tag : int
}
and ty_node =
| BS of Lenvar.id
| Bool
| G of Groupvar.id
| TySym of Tysym.id
| Fq
| Prod of ty list
| Int
(* ** Equality, hashing, and hash consing *)
let equal_ty : ty -> ty -> bool = (==)
let hash_ty t = t.ty_tag
let compare_ty t1 t2 = t1.ty_tag - t2.ty_tag
module Hsty = Hashcons.Make (struct
type t = ty
let equal t1 t2 =
match t1.ty_node, t2.ty_node with
| BS lv1, BS lv2 -> Lenvar.equal lv1 lv2
| Bool, Bool -> true
| G gv1, G gv2 -> Groupvar.equal gv1 gv2
| TySym ts1, TySym ts2 -> Tysym.equal ts1 ts2
| Fq, Fq -> true
| Prod ts1, Prod ts2 -> list_eq_for_all2 equal_ty ts1 ts2
| _ -> false
let hash t =
match t.ty_node with
| BS lv -> hcomb 1 (Lenvar.hash lv)
| Bool -> 2
| G gv -> hcomb 3 (Groupvar.hash gv)
| TySym gv -> hcomb 4 (Tysym.hash gv)
| Fq -> 5
| Prod ts -> hcomb_l hash_ty 6 ts
| Int -> 7
let tag n t = { t with ty_tag = n }
end)
(** Create [Map], [Set], and [Hashtbl] modules for types. *)
module Ty = StructMake (struct
type t = ty
let tag = hash_ty
end)
module Mty = Ty.M
module Sty = Ty.S
module Hty = Ty.H
(* ** Constructor functions *)
let mk_ty n = Hsty.hashcons {
ty_node = n;
ty_tag = (-1)
}
let mk_BS lv = mk_ty (BS lv)
let mk_G gv = mk_ty (G gv)
let mk_TySym ts = mk_ty (TySym ts)
let mk_Fq = mk_ty Fq
let mk_Bool = mk_ty Bool
let mk_Int = mk_ty Int
let mk_Prod tys =
match tys with
| [t] -> t
| _ -> mk_ty (Prod tys)
(* ** Indicator and destructor functions *)
let is_G ty = match ty.ty_node with
| G _ -> true
| _ -> false
let is_Fq ty = match ty.ty_node with
| Fq -> true
| _ -> false
let is_Prod ty = match ty.ty_node with
| Prod _ -> true
| _ -> false
let destr_G_exn ty =
match ty.ty_node with
| G gv -> gv
| _ -> raise Not_found
let destr_BS_exn ty =
match ty.ty_node with
| BS lv -> lv
| _ -> raise Not_found
let destr_Prod_exn ty =
match ty.ty_node with
| Prod ts -> ts
| _ -> raise Not_found
let destr_Prod ty =
match ty.ty_node with
| Prod ts -> Some ts
| _ -> None
(* ** Pretty printing *)
let pp_group fmt gv =
if Groupvar.name gv = ""
then F.fprintf fmt "G"
else F.fprintf fmt "G_%s" (Groupvar.name gv)
let rec pp_ty fmt ty =
match ty.ty_node with
| BS lv -> F.fprintf fmt "BS_%s" (Lenvar.name lv)
| Bool -> F.fprintf fmt "Bool"
| Fq -> F.fprintf fmt "Fq"
| TySym ts -> F.fprintf fmt "%s" (Tysym.name ts)
| Prod ts -> F.fprintf fmt "(%a)" (pp_list " * " pp_ty) ts
| Int -> F.fprintf fmt "Int"
| G gv ->
if Groupvar.name gv = ""
then F.fprintf fmt "G"
else F.fprintf fmt "G_%s" (Groupvar.name gv)

It's hard to walk through this code because quite a bit is missing (definitions of Id, Hashcons, StructMake). But in general this code manipulates data structures that represent types.
You can read about hash consing here: https://en.wikipedia.org/wiki/Hash_consing (which is what I just did myself). In essence it is a way of maintaining a canonical representation for a set of structures (in this case, structures representing types) so that two structures that are equal (having constituents that are equal) are represented by the identical value. This allows constant-time comparison for equality. When you do this with strings, it's called "interning" (a technique from Lisp I've used many times).
To add arrays, you need to know whether the array type will include the length of the array or just the type of its elements. The semi-mysterious type BS seems to include a length, which suggests you may want to include the length in your reprsentation.
If I were doing this project I would look for every occurence of Prod (which represents tuples) and I'd add a type representing Array in an analogous way. Instead of a list of constituent types (as for a tuple) you have one constituent type and (I would guess) a variable representing the length of the array.
Before starting out I'd look for some documentation, on what BS represents for one thing. I also have no idea what "groups" are, but maybe you could worry about it later.
Update
Here's what I mean by copying Prod. Keep in mind that I am basing this almost entirely on guesswork. So, many details (or even the entire idea) could be wrong.
The current definition of a type looks like this:
and ty_node =
| BS of Lenvar.id
| Bool
| G of Groupvar.id
| TySym of Tysym.id
| Fq
| Prod of ty list
| Int
If you add a representation for Array after Prod you get something like this:
and ty_node =
| BS of Lenvar.id
| Bool
| G of Groupvar.id
| TySym of Tysym.id
| Fq
| Prod of ty list
| Array of Lenvar.id * ty
| Int
You would then go through the rest of the code adding support for the new Array variant. The compiler will help you find many of the places that need fixing.

Related

Make dictionary from a chart setup

I'm trying to use keys (sizes of pipe) that have outlets of different sizes. Each outlet has its own set of sizes. I created dictionaries within a dictionary style which is called from a pickerView. But I can't call individual items from the buried dictionaries/arrays...
-------> _____
| | |
M ___| |___ size >>> 1/2"
|_|__ _ __ | ___|___
|______|______| | |
| | | outlets >>> 1/2" 3/8"
|__C___|___C__| /\ /\
/ \ / \
C M C M
I have already tried this setup with a structure and also tried individual dictionaries that all call to each other:>>
var out2 = ["1": [["1": [1.5 , 1.5]], ["3/4": [1.5 , 1.5]], ["1/2": [1.5 , 1.5]]]]
This does work but I can't call individual pieces from it.
struct teeDict {
var out1: [(size: String) :
[[(outlet1: String) :
[(c: Double) , (m: Double)]],
[(outlet2: String) :
[(c: Double) , (m: Double)]]]] =
["1/2" :
[["1/2" :
[1.0 , 1.0]],
["3/8" :
[1.0 , 1.0]]]]
}
I tried to create a dictionary instead of using arrays but nothing is recognized. How do I get this to work?? Thanks.
SOURCE DATA (for clarification)

Cannot return an array in go function that is invoked by js function. panic: ValueOf: invalid value

There is a gocode, which is compiled into a wasm file. I want one of the functions to return an array, but when I do so I see a panic: ValueOf: invalid value error. js.ValueOf function seems to be able to handle an array:
...
case []interface{}:
a := arrayConstructor.New(len(x))
for i, s := range x {
a.SetIndex(i, s)
}
return a
...
but still panics, when I give it a []int value.
package main
import (
"fmt"
"syscall/js"
)
var signal = make(chan int)
func keepAlive() {
for {
<-signal
}
}
func main() {
js.Global().Set("PanicStation", js.FuncOf(PanicStation))
keepAlive()
}
func PanicStation(this js.Value, args []js.Value) interface{} {
arr := make([]int, 1)
return arr
}
Using []interface{}
[]int is not the same as []interface{}. If []interface{} suits you, create and return that:
arr := make([]interface{}, 1)
For example, if you return this slice:
func PanicStation(this js.Value, args []js.Value) interface{} {
return []interface{}{1, "two"}
}
Running PanicStation() in the JavaScript console will output:
> PanicStation()
> (2) [1, "two"]
Returning a typed array
Documentation of js.ValueOf() details what types are supported and how they are converted:
| Go | JavaScript |
| ---------------------- | ---------------------- |
| js.Value | [its value] |
| js.TypedArray | typed array |
| js.Func | function |
| nil | null |
| bool | boolean |
| integers and floats | number |
| string | string |
| []interface{} | new array |
| map[string]interface{} | new object |
Note that it is possible to return a value which will be a typed array in JavaScript. For that, use js.TypedArray in Go (obtained by js.TypedArrayOf()). The supported types are:
The supported types are []int8, []int16, []int32, []uint8, []uint16, []uint32, []float32 and []float64. Passing an unsupported value causes a panic.
Here's an example how to do it:
func PanicStation(this js.Value, args []js.Value) interface{} {
return js.TypedArrayOf([]int32{1, 2})
}
This time calling PanicStation() from JavaScript, the output will be:
> PanicStation()
> Int32Array(2) [1, 2]

Using Array.Count and match cases F#

I am not sure yet what the problem is, I am trying to go through a ResizeArray and matching the item with the data type, and depending on this, take away the value in a specific field (iSpace) from thespace(which is how much space the inventory has), before returning the final value.
A snippet of my code :
let spaceleft =
let mutable count = 0 //used to store the index to get item from array
let mutable thespace = 60 //the space left in the inventory
printf "Count: %i \n" inventory.Count //creates an error
while count < inventory.Count do
let item = inventory.[count]
match item with
|Weapon weapon ->
thespace <- (thespace - weapon.iSpace)
|Bomb bomb ->
thespace <-(thespace - bomb.iSpace)
|Potion pot ->
thespace <- (thespace - pot.iSpace)
|Armour arm ->
thespace <- (thespace - arm.iSpace)
count <- count+1
thespace
I get an error about Int32, that has to do with the
printf "Count: %i \n" inventory.Count
line
Another problem is that thespace doesn't seem to change, and always returns as 60, although I have checked and inventory is not empty, it always has at least two items, 1 weapon and 1 armour, so thespace should atleast decrease yet it never does.
Other snippets that may help:
let inventory = ResizeArray[]
let initialise =
let mutable listr = roominit
let mutable curroom = 3
let mutable dead = false
inventory.Add(Weapon weap1)
inventory.Add(Armour a1)
let spacetogo = spaceleft //returns 60, although it should not
Also, apart from the iniitialise function, other functions seem not to be able to add items to the inventory properly, eg:
let ok, input = Int32.TryParse(Console.ReadLine())
match ok with
|false ->
printf "The weapon was left here \n"
complete <- false
|true ->
if input = 1 && spaceleft>= a.iSpace then
inventory.Add(Weapon a)
printf "\n %s added to the inventory \n" a.name
complete <- true
else
printf "\n The weapon was left here \n"
complete <- false
complete
You have spaceLeft as a constant value. To make it a function you need to add unit () as a parameter. Here's that change including a modification to make it much simpler (I've included my dummy types):
type X = { iSpace : int }
type Item = Weapon of X | Bomb of X | Potion of X | Armour of X
let inventory = ResizeArray [ Weapon {iSpace = 2}; Bomb {iSpace = 3} ]
let spaceleft () =
let mutable thespace = 60 //the space left in the inventory
printf "Count: %i \n" inventory.Count
for item in inventory do
let itemSpace =
match item with
| Weapon w -> w.iSpace
| Bomb b -> b.iSpace
| Potion p -> p.iSpace
| Armour a -> a.iSpace
thespace <- thespace - itemSpace
thespace
spaceleft () // 55
The above code is quite imperative. If you want to make it more functional (and simpler still) you can use Seq.sumBy:
let spaceleft_functional () =
printf "Count: %i \n" inventory.Count
let spaceUsed =
inventory
|> Seq.sumBy (function
| Weapon w -> w.iSpace
| Bomb b -> b.iSpace
| Potion p -> p.iSpace
| Armour a -> a.iSpace)
60 - spaceUsed
Just adding to the accepted answer: you can also match against record labels, as long as your inner types are records. Combine with an intrinsic type extension on the outer DU:
type X = { iSpace : int }
type Y = { iSpace : int }
type Item = Weapon of X | Bomb of Y | Potion of X | Armour of X
let inventory = ResizeArray [ Weapon {iSpace = 2}; Bomb {iSpace = 3} ]
let itemSpace = function
| Weapon { iSpace = s } | Bomb { iSpace = s }
| Potion { iSpace = s } | Armour { iSpace = s } -> s
type Item with static member (+) (a, b) = a + itemSpace b
60 - (Seq.fold (+) 0 inventory)
// val it : int = 55
Otherwise, you could resort to member constraint invocation expressions.
let inline space (x : ^t) = (^t : (member iSpace : int) (x))

SML - read file and convert to datatype

I defined datatype
datatype DT = D1 of string
| D2 of string
| D3 of string
| D4 of string*string
In a file there are some data like
D1("str1")
D4("str2","str3")
...
I need a list with data from this file. But when I read the file, the type list is string... how can I make this list type "DT type"?
Data.txt
D1("str1")
D4("str2","str3")
D2("str4")
datatype DT = D1 of string
| D2 of string
| D3 of string
| D4 of string*string
val infile = "Data.txt" ;
fun readlist (infile : string) =
let
val ins = TextIO.openIn infile
fun loop ins =
case TextIO.inputLine ins of
SOME line => line :: loop ins
| NONE => []
in
loop ins before TextIO.closeIn ins
end;

multi-directional infinte sequence - ML

I want to use the datatype sequence that is defined as follows:
datatype 'a seq = Nil | Cons of 'a * (unit-> 'a seq);
exception EmptySeq;
fun head(Cons(x,_)) = x | head Nil = raise EmptySeq;
fun tail(Cons(_,xf)) = xf() | tail Nil = raise EmptySeq;
which has to option to iterate over functions backward and forward:
datatype direction = Back | Forward;
datatype 'a bseq = bNil | bCons of 'a * (direction -> 'a bseq);
and i defined those as well:
fun bHead(bCons(x,_)) = x | bHead bNil = raise EmptySeq;
fun bForward(bCons(_,xf)) = xf(Forward) | bForward bNil = raise EmptySeq;
fun bBack(bCons(_,xf)) = xf(Back) | bBack bNil = raise EmptySeq;
Now, what I'm trying to do is to create a function "create_seq" that gets an int "k" and returns an infinte sequence which can be iterated back and forth.
for example:
- create_seq 2;
val it = bCons (2,fn) : int bseq
- bForward it;
val it = bCons (3,fn) : int bseq
- bForward it;
val it = bCons (4,fn) : int bseq
- bBack it;
val it = bCons (3,fn) : int bseq
- bBack it;
val it = bCons (2,fn) : int bseq
- bBack it;
val it = bCons (1,fn) : int bseq
- bBack it;
val it = bCons (0,fn) : int bseq
- bBack it;
val it = bCons (~1,fn) : int bseq
this is what I've been trying to do and can't figure out why it doesn't work:
fun create_seq k = (k,fun check Forward = create_seq(k+1)
| check Back = create_seq(k-1));
nor this:
fun create_seq k = (k,fn x => case x of Forward => create_seq(k+1)
| Back => create_seq(k-1));
or even this:
fun create_seq k = (k,fn Forward => create_seq(k+1)
| Back => create_seq(k-1));
It seems I forgot the constructor:
fun intbseq(k:int) = bCons(k,fn Forward => intbseq(k+1)| Back => intbseq(k-1));
this should work.

Resources