Is it possible to use a conditional statement in an Idiom Bracket in Idris? - syntactic-sugar

An expression like the following is perfectly valid in Idris:
let x = Just 5 in let y = Just 6 in [|x / y|]
Could someone write an expression like the following?
let x = Just 5 in let y = Just 6 in [| if x == 0 then 0 else y|]
I can't seem to get it to compile.

I was able to get this working by taking care of two problems:
if _ then _ else _ doesn't seem to propagate the idiom bracket to its subexpressions
The default definition of if _ then _ else _ is (of course) lazy in its two branches, and Lazy' LazyEval doesn't seem to lift instances.
Once these two were worked around, I was able to get it working in an idiom bracket. Note however that this wouldn't work for an applicative where taking both branches has an observable effect.
strictIf : Bool -> a -> a -> a
strictIf True t e = t
strictIf False t e = e
syntax "if" [b] "then" [t] "else" [e] = strictIf b t e
test : Maybe Float
test = let x = Just 5
y = Just 6
in [| if [| x == pure 0 |] then [|0|] else y |]

Related

F# Downcasting arrays without reflection

I am working on a program where the user can send me all sort of objects at runtime, and I do not know their type in advance (at compile time). When the object can be down-cast to an (F#) array, of any element type, I would like to perform some usual operations on the underlying array. E.g. Array.Length, Array.sub...
The objects I can get from the users will be of things like box [| 1; 2; 3 |] or box [| "a"; "b"; "c" |], or any 'a[], but I do not know 'a at compile time.
The following does not work :
let arrCount (oarr: obj) : int =
match oarr with
| :? array<_> as a -> a.Length
| :? (obj[]) as a -> a.Length
// | :? (int[]) as a -> a.Length // not an option for me here
// | :? (string[]) as a -> a.Length // not an option for me here
// | ...
| _ -> failwith "Cannot recognize an array"
E.g both arrCount (box [| 1; 2; 3 |]) and arrCount (box [| "a"; "b"; "c" |]) fail here.
The only solution I found so far is to use reflection, e.g. :
type ArrayOps =
static member count<'a> (arr: 'a[]) : int = arr.Length
static member sub<'a> (arr: 'a[]) start len : 'a[] = Array.sub arr start len
// ...
let tryCount (oarr: obj) =
let ty = oarr.GetType()
if ty.HasElementType && ty.BaseType = typeof<System.Array> then
let ety = ty.GetElementType()
let meth = typeof<ArrayOps>.GetMethod("count").MakeGenericMethod([| ety |])
let count = meth.Invoke(null, [| oarr |]) :?> int
Some count
else
None
My question: is there a way to use functions such as Array.count, Array.sub, etc... on arguments of the form box [| some elements of some unknown type |] without using reflection?
Since F# is statically type-safe it tries to prevent you from doing this, which is why it isn't trivial. Casting it to an array<_> will not work because from an F# standpoint, array<obj> is not equal to array<int> etc, meaning you would have to check for every covariant type.
However, you can exploit the fact that an array is also a System.Array, and use the BCL methods on it. This doesn't give you Array.length etc, because they need type-safety, but you can essentially do any operation with a little bit of work.
If you do have a limited set of known types that the obj can be when it is an array, I suggest you create a DU with these known types and create a simple converter that matches on array<int>, array<string> etc, so that you get your type-safety back.
Without any type safety you can so something like this:
let arrCount (x: obj) =
match x with
| null -> nullArg "x cannot be null"
| :? System.Array as arr -> arr.GetLength(0) // must give the rank
| _ -> -1 // or failwith
Usage:
> arrCount (box [|1;2;3|]);;
val it : int = 3
> arrCount (box [|"one"|]);;
val it : int = 1
This other answer on SO has a good way of explaining why allowing such casts makes the .NET type system unsound, and why it isn't allowed in F#: https://stackoverflow.com/a/7917466/111575
EDIT: 2nd alternative
If you don't mind boxing your entire array, you can expand on the above solution by converting the whole array, once you know it is an array. However, the first approach (with System.Array) has O(1) performance, while this approach is, necessarily, O(n):
open System.Collections
let makeBoxedArray (x: obj) =
match x with
| null -> nullArg "x cannot be null"
| :? System.Array as arr ->
arr :> IEnumerable
|> Seq.cast<obj>
|> Seq.toArray
| _ -> failwith "Not an array"
Usage:
> makeBoxedArray (box [|1;2;3|]);; // it accepts untyped arrays
val it : obj [] = [|1; 2; 3|]
> makeBoxedArray [|"one"|];; // or typed arrays
val it : obj [] = [|"one"|]
> makeBoxedArray [|"one"|] |> Array.length;; // and you can do array-ish operations
val it : int = 1
> makeBoxedArray (box [|1;2;3;4;5;6|]) |> (fun a -> Array.sub a 3 2);;
val it : obj [] = [|4; 5|]
Curiously, this is a non-issue in languages like C# and VB, while you may have to do some extra work for F#. You can't do this in general, because F# doesn't have co-variant types.
Vote for that feature here!.
But we do have flexible types which give us rather limited contra-variance, which we can work with.
let anyLength (arr : #obj[]) =
arr |> Array.length
And,
let iarr = [| 1; 2; 3|]
let sarr = [|"a"; "b" |]
anyLength iarr // 3
anyLength sarr // 2

Assign variable to array element where variable and array can be modified independently in ocaml

Here is the problem I can't get around, I'm working in ocaml to copy the elements of an array to a new array. I want to be able to modify these arrays independently from each other, but no matter what I try, a change to one array is reflected in the other array as well.
Here is a simplified example:
type sampleType = { a : int; b : int array };;
let x = {a = 5; b = [|1, 2, 3|] };;
let y = x.b;;
Array.set y 1 6;;
After running these commands I want:
y - : int array = [|1; 6; 3|]
x - : sampleType = {a = 5; b = [|1; 2; 3|]}
Instead x is being changed along with y, and
x - : sampleType = {a = 5; b = [|1; 6; 3|]}
Any solutions to this problem?
As you see from your experiments, this code:
let y = x.b
makes y refer to the very same array as x.b. It doesn't create an independent array. To create an independent array, you need to copy:
let y = Array.copy x.b
I was specifically using 3d arrays, realized I had to apply Array.copy at the lowest level of the 3d array, rather than at the top level.
let arr = Array.init 3 (fun _ -> Array.init 3 (fun _ -> (Array.init 3 (fun _ -> {faces = [|0;1;2;3;4|]}))));;
let drr = Array.init 3 (fun i -> Array.init 3 (fun j -> Array.copy arr.(i).(j)));;
This gave me the result I needed.

Taking two elements from an array and adding them, then adding them back into the array

Im trying to create a calculator in f# using two arrays, one which stores the numbers and the other to store the operator symbols. I need the symbols array to pattern match the symbol and depending on the operator take the first two elements from the array and do the operation and add the new number into the head of the 2nd array.
open System
[<EntryPoint>]
let main argv =
printfn "%A" argv
let Add x y = x + y
let Sub x y = x - y
let Div x y = x * y
let Mul x y = x / y
printfn "1 > Calculator \n2 > Load from txt file"
let chosenIn = Console.ReadLine();
//This is where I need to do the operation and after call the sum function
//again until there's only one element left in the number array
let rec sum num (numArray : int[]) sym (symArray : string[]) () =
let rec calc () =
printfn "Enter Sum"
let input = Console.ReadLine()
let intInput = input.Split()
let numArray = [|for num in intInput do
let v , vp = System.Int32.TryParse(num)
if v then yield vp|]
let symbolArray = [|for symbol in intInput do
match symbol with
| "+" -> yield symbol
| "-" -> yield symbol
| "/" -> yield symbol
| "*" -> yield symbol
| _ -> ignore 0|]
calc()
match chosenIn with
| "1" -> calc()
| "2" -> printfn "File"
| _ -> printfn "Invalid"
0 // return an integer exit code
In response to the answer #Liam Donnelly posted to his own question: I'll leave aside questions like "is that really the best way of solving the problem", just commenting on how to better write the code you currently have.
Array slicing and concatenating the way you are doing it here can be written as
let newNumArray = Array.append [| result |] numArray.[2..]
However, I would use F# lists rather than arrays for your task. With lists, you can do pattern matching to access the first 2 elements. Pattern matching, in my view, wins over direct indexing because you can directly encode corner cases, and get the F# compiler to remind you of corner cases. Do the same thing for the operators. You can do both operators and operands in the same go. It will then look something like this:
let rec sum2 (numArray : int list) (symArray : string list) =
let newNum, newSym =
match numArray with
| [] -> failwith "No numbers left to process"
| arg1 :: [] -> failwith "There's only one number left to process"
| arg1 :: arg2 :: args ->
match symArray with
| op1 :: ops ->
let result =
match op1 with
| "+" -> Add arg1 arg2
| "-" -> Sub arg1 arg2
| "*" -> Mul arg1 arg2
| _ -> failwithf "Operator not recognized: '%s'" op1
// Return the result, concatenate the non-processed
// numbers. Return the non-processed operators
result :: args, ops
| _ -> failwith "I've run out of operators?"
<snip>
Also, returning a "default result" if you don't recognize the operators is something that I consider very risky (even though the practice is rather widespread)
If you use lists (F# lists, that is), you can directly access the elements at indices 1.. via head: let newSymArray = symArray.Head or use List.head
Take a step back each time you see yourself writing a for loop in F#. They are cumbersome to write and error-prone. Most of the typical use-cases for loops are covered by F# library functions, so have a good read through those. Your printing loop can be written way shorter by doing:
newNumArray
|> Seq.iter (printfn "%i")
I've managed to make the function which performs the task I needed for it to do and I'm sure there's a much more code efficient way of taking the first elements of the arrays by using Array.copy with filters but I'm new to f# so I just it the way I was confident with
let rec sum (numArray : int[]) (symArray : string[]) =
let result = match symArray.[0] with
| "+" -> Add numArray.[0] numArray.[1]
| "-" -> Sub numArray.[0] numArray.[1]
| "*" -> Mul numArray.[0] numArray.[1]
| _ -> 0
let newNumArray = [|
for i = 0 to numArray.Length - 1 do
if i = 0 then yield result
if i > 1 then yield numArray.[i]|]
let newSymArray = [|
for i = 0 to symArray.Length - 1 do
if i > 0 then yield symArray.[i]|]
if newNumArray.Length > 1 then
sum newNumArray newSymArray
else
for i = 0 to newNumArray.Length - 1 do
printfn "%i" (newNumArray.[i])

How to convert an Array2D with option int elements to Array2D with int elements

I am trying to convert Array2D optionArr with option int elements to Array2D arr with int elements:
let arr =
optionArr
|> Array2D.map (fun x ->
match Option.toArray x with
| [| |] -> -1
| [| v |] -> v)
However, Visual Studio 2013 underlines everything starting from Array2D.map ... until ... -> v) with red and says:
Type mismatch. Expecting a
int [,] option -> 'a
but given a
'b [,] -> 'c [,]
The type 'int [,] option' does not match the type ''a [,]'
I have been trying to "fix" my code but I no idea what I am doing wrong nor what the above error message alludes to.
EDIT
I applied Reed Copsey's answer (which itself uses Marcin's approach), yet still got the above error message when I realised that the message clearly states that Array2D arr is of type int [,] option and not int option [,]. Applying the same logic my corrected code is as follows:
let arr = defaultArg optionArr (Array2D.zeroCreate 0 0)
defaultArg seems to be quite useful for treating Option values as 'normal' ones.
Marcin's approach works fine. This can also be done a bit more simply using defaultArg directly:
// Create our array
let optionArr = Array2D.create 10 10 (Some(1))
let noneToMinusOne x = defaultArg x -1
let result = optionArr |> Array2D.map noneToMinusOne
let arr optionArr =
optionArr
|> Array2D.map (fun x ->
match x with
| Some(y) -> y
| None -> -1)
usage
let getOptionArr =
Array2D.create 10 10 (Some(1))
let result = arr getOptionArr

F# sorting array

I have an array like this,
[|{Name = "000016.SZ";
turnover = 3191591006.0;
MV = 34462194.8;};
{Name = "000019.SZ";
turnover = 2316868899.0;
MV = 18438461.48;};
{Name = "000020.SZ";
turnover = 1268882399.0;
MV = 7392964.366;};
.......
|]
How do I sort this array according to "turnover"? Thanks
(does not have much context to explain the code section? how much context should I write)
Assuming that the array is in arr you can just do
arr |> Array.sortBy (fun t -> t.turnover)
I know this has already been answered beautifully; however, I am finding that, like Haskell, F# matches the way I think and thought I'd add this for other novices :)
let rec sortData =
function
| [] -> []
| x :: xs ->
let smaller = List.filter (fun e -> e <= x) >> sortData
let larger = List.filter (fun e -> e > x) >> sortData
smaller xs # [ x ] # larger xs
Note 1: "a >> b" is function composition and means "create a function, f, such that f x = b(a(x))" as in "apply a then apply b" and so on if it continues: a >> b >> c >>...
Note 2: "#" is list concatenation, as in [1..100] = [1..12] # [13..50] # [51..89] # [90..100]. This is more powerful but less efficient than cons, "::", which can only add one element at a time and only to the head of a list, a::[b;c;d] = [a;b;c;d]
Note 3: the List.filter (fun e ->...) expressions produces a "curried function" version holding the provided filtering lambda.
Note 4: I could have made "smaller" and "larger" lists instead of functions (as in "xs |> filter |> sort"). My choice to make them functions was arbitrary.
Note 5: The type signature of the sortData function states that it requires and returns a list whose elements support comparison:
_arg1:'a list -> 'a list when 'a : comparison
Note 6: There is clarity in brevity (despite this particular post :) )
As a testament to the algorithmic clarity of functional languages, the following optimization of the above filter sort is three times faster (as reported by VS Test Explorer). In this case, the list is traversed only once per pivot (the first element) to produce the sub-lists of smaller and larger items. Also, an equivalence list is introduced which collects matching elements away from further comparisons.
let rec sort3 =
function
| [] -> []
| x::xs ->
let accum tot y =
match tot with
| (a,b,c) when y < x -> (y::a,b,c)
| (a,b,c) when y = x -> (a,y::b,c)
| (a,b,c) -> (a,b,y::c)
let (a,b,c) = List.fold accum ([],[x],[]) xs
(sort3 a) # b # (sort3 c)

Resources