Standard ML programming, array function - arrays

In ML I have an array of chars! I am trying to find an array function in order to give the function the char #"T" and returns me the position of this element in array. I tried the find function and it doesn't work like that!

findi from the Array structure will do what you want. For an array of type 'a array, findi takes a (int * 'a) -> bool and a 'a array and returns an (int * 'a) option. So if you want to take a character and just return the character's position, you just need figure out the appropriate arguments to pass to findi and the appropriate way to interpret the result.
So for instance:
- fun findPos char = (Option.map (fn (i,_) => i)) o (Array.findi (fn (_,c) => c = char));
stdIn:2.65 Warning: calling polyEqual
val findPos = fn : ''a -> ''a array -> int option
- findPos #"c" (Array.fromList (explode "abcdef"));
val it = SOME 2 : int option
- findPos #"z" (Array.fromList (explode "abcdef"));
val it = NONE : int option

Related

F# why arrays are not scrambled in a different way when mapping a function to scramble each array in an array

I wrote a function to scramble an array and map an array of arrays to scramble each one different but they are scrambled the same way
let rand = System.Random()
let shuffle (rand : System.Random)(array :int[] ) = let rng = new Random()
let mutable n = array.Length
while (n > 1) do
let k = rng.Next(n)
n <- n - 1
let temp = array.[n]
array.[n] <- array.[k]
array.[k] <- temp
array
let playsarray = shuffle rand
let scrambledarray = Array.map (fun x -> playsarray x )
let playsarra = fun (array : int[]) -> array |> playsarray
let smallarray = [1..10].ToArray()
let megaarray = Array.create 10 smallarray
let megarrayscrambled = megaarray |> scrambledarray
megarrayscrambled |> Seq.iter (fun y -> printfn "Ar: %A" y)
after running the code all the 10 arrays have the same order in the data ej
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|]
Ar: [|5; 1; 7; 2; 8; 10; 6; 3; 9; 4|] and so on ...
There are two problems with your code.
First, your shuffle function takes a rand parameter but isn't actually using it: inside the function you create a new System.Random instance and use it instead of using the one passed in. The docs for the System.Random constructor mention (in the examples) that the default constructor uses the current time as a seed, so if two Random objects are created in quick succession, they would have the same seed and thus produce the same values. To fix this problem, you just need to stop creating a new Random instance in your shuffle function and instead use the one passed in (I renamed it from rand to rng so that the rest of your code wouldn't need changing). Here's your shuffle function with that change made (and with much easier-to-read indentation: you don't have to start the first line of the function on the same line as the = sign; you can put it on the next line and just indent one indentation level, four spaces):
let shuffle (rng : System.Random) (array : int[]) =
let mutable n = array.Length // The number of items left to shuffle (loop invariant).
while (n > 1) do
let k = rng.Next(n) // 0 <= k < n.
n <- n - 1 // n is now the last pertinent index;
let temp = array.[n] // swap array[n] with array[k] (does nothing if k == n).
array.[n] <- array.[k]
array.[k] <- temp
array
BUT that won't solve your issues just yet, because you've also misunderstood how Array.create works. It creates an array of a given size, where each item in the array contains the value you passed in. I.e., every entry in your megarrayscrambled array contains a reference to the same smallarray. If you did megarrayscrambled.[0].[0] <- 999 you'd see that this changed every one of the ten entries in megarrayscrambled, because they're the same array.
What you actually wanted was to use Array.init, not Array.create. Array.init takes a function and runs that function once per item it's creating in the array you're building. This means that if that function returns [1..10].ToArray(), then each time it's called it will return a different array, and you'll therefore get the results you expect. (By the way, you can create an array more simply by doing [|1..10|], and that's what I'll use in the sample code below).
So just change your let megaarray line to:
let megaarray = Array.init 10 (fun _ -> [|1..10|])
and then you should see the results you were expecting.
BTW, one more little detail: in one line you have Array.map (fun x -> playsarray x), but that is just equivalent to Array.map playsarray, which is a little simpler to read.

Pattern matching an array

I've created a:
newType Board = Board (Array (Int, Int) Life)
, where
data Life = Alive|Dead
Im trying to make a function to save the board to a String by pattern matching:
showBoard:: Config -> String
showBoard Board(array ((0, 0), (w, h)) [(a:as)]) = *code*
But this only gives me "Parse error in pattern: array". I cant see what's wrong?
You can only pattern-match on data constructors. array is not a data constructor; it is a regular function that internal uses the Array data constructor(s) to create and return an Array value. The internal details
of an Array are not exposed, preventing you from pattern-matching on them.
Instead, you need use the functions provided for looking at an Array value. These can be composed with a function that does take arguments you can pattern match on.
-- bounds :: Array i e -> (i, i)
-- elems :: Array i e -> [e]
showConfig :: Board -> String
showConfig (Board arr) = showConfig' (bounds arr) (elems arr)
where showConfig' :: ((Int,Int),(Int,Int)) -> [Life] -> String
showConfig' ((0,0),(w,h)) (a:as) = ...
If you modify your Board type to
newtype Board = Board { getArray :: Array (Int, Int) Life }
you can rewrite showConfig in an applicative style:
showConfig = (showConfig' <$> boards <*> elems) . getArray
where showConfig' ((0,0),(w,h)) (a:as) = ...

Error SML NJ-Operator and Operand don't agree

When I try to compile my ML Program ,I get an error saying:"Operator and Operand don't agree".
candidates.sml:78.8-78.40 Error: operator and operand don't agree [tycon mismatch]
operator domain: int * (int * 'Z * 'Y) list
operand: int * (int * real) list
in expression:
tr (n,candidates)
I understand the error but I can't find a solution.
The part of the code where I get the error is:
fun agonas fileName =
let
fun tr(n,[])=[]
| tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
val (n,l,candidates) = parse fileName
val cand = tr(n,candidates)
in
my_solution(l,cand)
end;
,where the candidates are related with the part below:
fun parse file =
let
(* a function to read an integer from an input stream *)
fun next_int input =
Option.valOf (TextIO.scanStream (Int.scan StringCvt.DEC) input)
(* a function to read a real that spans till the end of line *)
fun next_real input =
Option.valOf (TextIO.inputLine input)
(* open input file and read the two integers in the first line *)
val stream = TextIO.openIn file
val n = next_int stream
val l = next_int stream
val _ = TextIO.inputLine stream
(* a function to read the pair of integer & real in subsequent lines *)
fun scanner 0 acc = acc
| scanner i acc =
let
val d = next_int stream
val (SOME v) = Real.fromString (next_real stream)
in
scanner (i - 1) ((d, v) :: acc)
end
in
(n, l, rev(scanner n []))
end;
fun my_solution ( n , l ,candidates ) = [2 ,3 ,5 ,4 ,6]
fun agonas fileName = my_solution ( parse fileName )
I would appreciate it if you could find the mistake.Thanks in advance.
The problem is that parse, using scanner, builds a list of pairs — (int * real) list — while tr expects to get a list of triples — (int * 'Z * 'Y) list.
Not knowing what tr is supposed to do, the quick and dirty fix would be to change
tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
into
tr(n,((a,b)::d))=((n-a+1),b)::(tr(n,d))
But that may be the wrong solution - it depends on what the code is supposed to do.
(Sometimes it helps to explicitly write out the types yourself - even before writing the code - instead of relying on type inference to catch the places where you need to do some more thinking.)
The error message says it all: the offending line calls trans, and that is a function that expects two arguments, the second being a list of triples. However, you are passing it a list of pairs instead (as produced by your scanner function).
You didn't show us the trans function, so I cannot be more specific about what the appropriate fix would be.

SML NJ , able to find max real of array, cant get index

i have an array of real values like [|1.2, 3.4, 5.3, 2.5|]
fun max_arr arr = foldl Real.max (sub (arr, 0)) arr;
works fine to find the max value 5.3 .
Then i would expect something like
fun max_arri arr = foldli (Real.max(sub (arr, 0))) arr;
to successfully return the location of max value 2.but it doesn't work.
(Error: unbound variable or constructor: max_arri)
I went through everything I could find online but the documentation about sml seems small...
according to the manual they both take the same data. so what would i need to change?
foldli f init arr
foldl f init arr
also i dont want to use lists because i change the data alot
They do not take the same input.
foldl :: ( 'a * 'b -> 'b) -> 'b -> 'a array -> 'b
foldli :: (int * 'a * 'b -> 'b) -> 'b -> 'a array -> 'b
As we can see from the types, the difference is that foldli takes a function that also takes an integer -- the index of the element.
The return type of the two functions are both 'b, so foldli does not return the index. Rather, this expression:
foldli (fn (i, a, b) => f (a, b)) init arr
Is the exact equivalent of this expression:
foldl f init arr
Now, if we want to return the index of an element, we need the 'b in the type of foldli to become int. However, finding the maximum relies on comparison of elements, so we also need the current maximum, just like in your max_arr function. The obvious solution is to use a tuple. 'b now becomes (real * int).
(* cElem = current element
* cI = current index
*)
fun fmax (i, elem : real, (cElem, cI)) =
if cElem > elem
then (cElem, cI)
else (elem, i)
fun max_arri arr = foldli fmax (sub (arr, 0), 0) arr
Of course, this is not the type we want our max_arri to return - we only want the index. The loose helper function isn't very nice either, but it's a bit long to have as a lambda. Instead, we wrap it all in a local:
local
fun fmax (i, elem : real, (cElem, cI)) =
if cElem > elem
then (cElem, cI)
else (elem, i)
fun max_arri' arr = foldli fmax (sub (arr, 0), 0) arr
in
fun max_arri arr = let val (_, i) = max_arri' arr
in i end
end

How can I convert indexes into a mutable array into state references in Haskell?

I'm recoding the game I asked a question, "How can I iterate over a quadruple linked 2-dimensional grid of data as if it were a 2-dimensional array?", for in Haskell.
In order to create the grid of data in the first place I used a very imperative style algorithm, shown below. The key feature it relies upon is that I can take an index into an array and create a reference out of it. An example, "&array[x][y]".
I need to be able to take an index into a mutable array and make a state reference out of it in Haskell. The type signature might therefore be
convertToSTRef :: i -> STArray s i a -> ST s (STRef s a)
I have looked over the documentation, tried both hoogle and hayoo, and not found a way to accomplish this.
P.S. Alternatively, if someone had a different algorithm that I could use, that would be great.
P.S.S. The simple imperative algorithm.
const size_t rows = 20;
const size_t columns = 59;
block tiles[columns][rows];
block * const start = &tiles[columns/2][rows/2];
for (size_t x = 0; x < columns; ++x)
for (size_t y = 0; y < rows; ++y)
{
tiles[x][y].floor = '^';
tiles[x][y].inhabitant = WALL;
tiles[x][y].side_block[EAST] = (x + 1 < columns) ? &tiles[x + 1][y] : NULL;
tiles[x][y].side_block[SOUTH] = (y + 1 < rows) ? &tiles[x][y + 1] : NULL;
tiles[x][y].side_block[WEST] = (x > 0) ? &tiles[x - 1][y] : NULL;
tiles[x][y].side_block[NORTH] = (y > 0) ? &tiles[x][y - 1] : NULL;
}
You can represent a "pointer" by a cursor, that is, a data structure containing an array reference and an offset.
data Cursor t i a = Cursor (t i a) i
makeCursor :: STArray s i a -> i -> Cursor (STArray s) i a
makeCursor = Cursor
readCursor :: Ix i => Cursor (STArray s) i a -> ST s a
readCursor (Cursor arr i) = readArray arr i
writeCursor :: Ix i => a -> Cursor (STArray s) i a -> ST s ()
writeCursor x (Cursor arr i) = writeArray arr i x
It is not possible to point to the interior of a garbage-collected object in GHC. The garbage collector cannot understand such pointers. If an array is moved by the garbage collector, the garbage collector cannot update such pointers appropriately. If the garbage collector is given a pointer to the middle of an array, it cannot scan the entire array because it can't find the beginning of the array.

Resources