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

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

Related

Run-length encoding of a Repa array

I have a one-dimensional Repa array that consists of 0's and 1's and I want to calculate its run-length encoding.
E.g.: Turn [0,0,1,1,1,0,0,0,1,0,1,1] into [2,3,3,1,1,2] or something similar. (I'm using a list representation because of readability)
Ideally, I would like the run-length of the 1's and ignore the 0's.
So [0,0,1,1,1,0,0,0,1,0,1,1] becomes [3,1,2].
I would like the result to be a (Repa) array as well.
How can I do this using Repa? I can't use map or traverse since they only give me one element at a time. I could try to fold with some special kind of accumulator but that doesn't seem to be ideal and I don't know it it's even possible (due to monad laws).
I'm currently just iterating over the array and returning a list without using any Repa function. I'm working on Booleans instead of 1's and 0's but the algorithm is the same. I'm converting this list to a Repa Array afterwards.
runLength :: Array U DIM1 Bool -> [Length]
runLength arr = go ([], 0, False) 0 arr
where
Z :. n = extent arr
go :: Accumulator -> Int -> Array U DIM1 Bool -> [Length]
go !acc#(xs, c, b) !i !arr | i == n = if c > 0 then c:xs else xs
| otherwise =
if unsafeIndex arr (Z :. i)
then if b
then go (xs, c+1, b) (i+1) arr
else go (xs, 1, True) (i+1) arr
else if b
then go (c:xs, 0, False) (i+1) arr
else go (xs, 0, False) (i+1) arr

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) = ...

What is the fastest way to initialize an immutable unboxed int array in Haskell?

Is this the fastest way to initialize an immutable array in Haskell with non-default (non-zero) values? In the following examples I am simply initializing the array with values from 0 to (size-1).
Fastest so far (twice the speed of Code.ST below). Thanks to leftaroundabout:
...
import qualified Data.Vector.Unboxed as V
stArray :: Int -> V.Vector Int
stArray size =
V.generate size id
...
My original fastest:
module Code.ST where
import Data.Array.MArray
import Data.Array.ST
import Data.Array.Unboxed
stArray :: Int -> UArray Int Int
stArray size =
runSTUArray $ newArray (0,size-1) 0 >>= f 0
where
f i a
| i >= size = return a
| otherwise = writeArray a i i >> f (i + 1) a
stMain :: IO ()
stMain = do
let size = 340000000
let a = stArray size
putStrLn $ "Size: " ++ show size ++ " Min: " ++ show (a ! 0) ++ " Max: " ++ show (a ! (size - 1))
I have tried the simpler immutable ways of doing it and it is 2 to 3 times slower on my PC (YMMV). I also tried Repa but it falls over even with smaller than 340000000 size arrays (lots of HD trashing - I gave up before it finished).
Have you tried listArray from Data.Array.Unboxed? You can use them like this:
-- listArray :: (Ix i, IArray a e) => (i, i) -> [e] -> a i e
listArray (0,3) "abcdefgh" :: UArray Int Char
This will create
array (0,3) [(0,'a'),(1,'b'),(2,'c'),(3,'d')]
If you need a bit more flexibility you can use array from the same module.
-- array :: (Ix i, IArray a e) => (i, i) -> [(i, e)] -> a i e
array (0,3) (zip [1,3,0,2] "abcd") :: UArray Int Char
Which will produce
array (0,3) [(0,'c'),(1,'a'),(2,'d'),(3,'b')]
I don't really know whether it is fast or not, but certainly it is more convenient to use than hand-written ST loops.

Standard ML programming, array function

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

Something like mapM, but for arrays? (like arrayMap, but mapping an impure function)

I see that I can map a function over mutable arrays with mapArray, but there doesn't seem to be something like mapM (and mapM_). mapArray won't let me print its elements, for example:
import Data.Array.Storable
arr <- newArray (1,10) 42 :: IO -- answer to Life, Universe and Everything
x <- readLn :: IO Int
mapArray (putStrLn.show) arr -- <== this doesn't work!
The result will be:
No instances for (MArray StorableArray Int m,
MArray StorableArray (IO ()) m)
arising from a use of `mapArray' at <interactive>:1:0-27
Possible fix:
add an instance declaration for
(MArray StorableArray Int m, MArray StorableArray (IO ()) m)
In the expression: mapArray (putStrLn . show) arr
In the definition of `it': it = mapArray (putStrLn . show) arr
Is there something like that in Haskell (or in GHC even if not standard Haskell)?
Also, I found no foldr/foldl functions for arrays (mutable or not). Do they exist?
Thanks a lot!
Import the module Data.Traversable. It defines a typeclass for just what you want with instances already defined for array and all sorts of things. It has generalized versions of sequence and mapM, plus some even more general functions that you probably won't bother with very often.
Just a simple
import Data.Traversable as T
T.mapM doIOStuff arr
works fine.
Perhaps use one of the other array libraries, if you're doing a lot of mutation? Like uvector?
Otherwise,
forM_ [1..n] \$ \i ->. unsafeWrite x i
should be fine.
For the example of printing all the elements: you can use "mapM_ print . elems".
But it sounds like you want to create a new array where each value is the result of a monadic action of the previous one? In that case:
arrayMapM :: (Monad m, Ix i) => (a -> m b) -> Array i a -> m (Array i b)
arrayMapM func src =
liftM (listArray (bounds src)) . mapM func . elems $ src

Resources