Pattern matching for lambdas? - functional-programming

Is it possible to have pattern matching of arguments and casing for an anonymous function? If so, what is the syntax?
Ipsum lorem

It's exactly the same as for named functions:
- (fn 0 => 1 | x => 34) 1;
val it = 34 : int
- (fn (_::y::_) => y) [1,2,3];
val it = 2 : int
(A warning was omitted in the second example.)

Related

Int64 usage in recursive functions

I have the following code written in Ocaml to try and generate the first 50 catalan numbers:
let rec f n:int64=
if n<1 then 1L
else (4*n-2)*f((n-1L))/(n+1L)
;;
for i = 0 to 50 do
Printf.printf "%d\n"(f i)
done;
But the problem is that the recursion function doesn't seem to accept Int64 values and seems to want Int instead despite me notating n as int64:
File "/proc/self/fd/0", line 3, characters 19-21:
3 | else (4*n-2)*f((n-1L))/(n+1L)
^^
Error: This expression has type int64 but an expression was expected of type
int
exit status 2
Is there a way to ensure I can int64 numbers here with recursion?
Your problem isn't recursion per se, it's that the operators in OCaml are strongly typed. So the - operator is of type int -> int -> int.
Without getting into lots of fussing with the syntax, the easiest fix is probably to use the named functions of the Int64 module. You can use Int64.sub rather than -, for example.
You can use the notation Int64.(... <expr> ...) to avoid repeating the module name. If you rewrite your code this way, you get something like this:
let rec f (n : int64) : int64 =
Int64.(
if n < 1L then 1L
else
mul (sub (mul 4L n) 2L)
(f (div (sub n 1L) (add n 1L)))
)
Looking at the results computed by this function, they don't look like Catalan numbers to me. In fact the 50th Catalan number is too large to be represented as an int64 value.
So there is still some work to do. But this is how to get past the problem you're seeing (IMHO).
If you really want to work with such large numbers, you probably want to look at the Zarith module.
Submitted as an additional suggestion to Jeffrey's answer: whether using Int64 or Zarith, you might create a module defining arithmetic operators and then locally open that to clean up your code.
E.g.
module Int64Ops =
struct
let ( + ) = Int64.add
let ( - ) = Int64.sub
let ( * ) = Int64.mul
let ( / ) = Int64.div
end
let rec f n =
Int64Ops.(
if n < 1L then 1L
else (4L * n - 2L) * f (n - 1L) / (n + 1L)
)
Or you could use a functor to make it easier to work with multiple different types of numbers.
module type S =
sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end
module BasicArithmeticOps (X : S) =
struct
type t = X.t
let ( + ) = X.add
let ( - ) = X.sub
let ( * ) = X.mul
let ( / ) = X.div
end
# let module A = BasicArithmeticOps (Float) in
A.(8. + 5.1);;
- : float = 13.1
# let module A = BasicArithmeticOps (Int) in
A.(8 + 3);;
- : int = 11
# let module A = BasicArithmeticOps (Int64) in
A.(4L + 3L);;
- : int64 = 7L

Return a list of even numbers from a list of integer pairs in sml

I have the following question "Given a list of integer pairs, write a function to return a list of even numbers in that list in sml".
this is what I've achieved so far
val x = [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
fun isEven(num : int) =
if num mod 2 = 0 then num else 0;
fun evenNumbers(list : (int * int) list) =
if null list then [] else
if isEven(#1 (hd list)) <> 0
then if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
else []
else if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: evenNumbers(tl list)
else [];
evenNumbers(x);
the result should be like this [6,2,4,6,8,10]
any help would be appreciated.
I see two obvious problems.
If both the first and second number are even, you do
#1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
which adds the first number twice and ignores the second.
If the first number is odd and the second even, you do
#1 (hd list) :: evenNumbers(tl list)
which adds the number that you know is odd and ignores the one you know is even.
Programming with selectors and conditionals gets complicated very quickly (as you've noticed).
With pattern matching, you could write
fun evenNumbers [] = []
| evenNumber ((x,y)::xys) = ...
and reduce the risk of using the wrong selector.
However, this still makes for complicated logic, and there is a better way.
Consider the simpler problem of filtering the odd numbers out of a list of numbers, not pairs.
If you transform the input into such a list, you only need to solve that simpler problem (and there's a fair chance that you've already solved something very similar in a previous exercise).
Exercise: implement this transformation. Its type will be ('a * 'a) list -> 'a list.
Also, your isEven is more useful if it produces a truth value (if you ask someone, "is 36 even?", "36" is a very strange answer).
fun isEven x = x mod 2 = 0
Now, evenNumbers can be implemented as "just" a combination of other, more general, functions.
So running your current code,
- evenNumbers [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
val it = [6,6,3,5,7,9] : int list
suggests that you're not catching all even numbers, and that you're catching some odd numbers.
The function isEven sounds very much like you want to have the type int -> bool like so:
fun isEven n =
n mod 2 = 0
Instead of addressing the logic error of your current solution, I would like to propose a syntactically much simpler approach which is to use pattern matching and fewer explicit type annotations. One basis for such a solution could look like:
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) = ...
Using pattern matching is an alternative to if-then-else: the [] pattern is equivalent to if null list ... and the (x,y)::pairs pattern matches when the input list is non-empty (holds at least one element, being (x,y). At the same time, it deconstructs this one element into its parts, x and y. So in the second function body you can express isEven x and isEven y.
As there is a total of four combinations of whether x and y are even or not, this could easily end up with a similarly complicated nest of if-then-else's. For this I might do either one of two things:
Use case-of (and call evenNumbers recursively on pairs):
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) =
case (isEven x, isEven y) of
... => ...
| ... => ...
Flatten the list of pairs into a list of integers and filter it:
fun flatten [] = ...
| flatten ((x,y)::pairs) = ...
val evenNumbers pairs = ...

Julia way of searching tokens in integer arrays

Let's say I have buffer=Int[1,2,3,2,3] and token=[2,3].
Is there any preferred way of searching the occurrence of token in buffer to find [2,4] as the answer.
Or, perhaps, is there any split equivalent function for the integer arrays in julia?
(I know how I can perform this operation using 2 nested loops. However, I am especially interested if there is a more Julian way of doing this.)
Because Julia doesn't have conditionals in list comprehensions, I would personally use filter(). Thus if arr = Int64[1,2,3,4,5,2,3,6,2,3,3,2,2]:
filter(x -> arr[x] == 2 && arr[x + 1] == 3, 1 : length(arr) - 1)
=> [2,6,9]
To make it a little more reusable:
pat = [2,3]
filter(x -> arr[x : x + length(pat) - 1] == pat, 1 : length(arr) - length(pat) + 1)
=> [2,6,9]
Julia does have built-ins like find([fun], A), but there's no way that I'm aware of to use them to return indexes of an ordered sublist.
Of course it's arguably more legible to just
ndxs = Int64[]
for i = 1:length(arr)-1
if arr[i] == 2 && arr[i+1] == 3
push!(ndxs, i)
end
end
=> [2,6,9]
For practice I have also made trial-and-errors and the following patterns have worked for Julia0.4.0. With A = Int[1,2,3,2,3] and pat = Int[2,3], the first one is
x = Int[ A[i:i+1] == pat ? i : 0 for i=1:length(A)-1 ]
x[ x .> 0 ] # => [2,4]
the second one is
x = Int[]
[ A[i:i+1] == pat ? push!(x,i) : 0 for i=1:length(A)-1 ]
#show x # => [2,4]
and the third one is
find( [ A[i:i+1] == pat for i=1:length(A)-1 ] ) # => [2,4]
(where find() returns the index array of true elements). But personally, I feel these patterns are more like python than julia way...

SML syntactical restrictions within recursive bindings?

There seems to be syntactical restrictions within SML's recursive bindings, which I'm unable to understand. What are these restrictions I'm not encountering in the second case (see source below) and I'm encountering when using a custom operator in the first case?
Below is the case with which I encountered the issue. It fails when I want to use a custom operator, as explained in comments. Of the major SML implementations I'm testing SML sources with, only Poly/ML accepts it as valid, and all of MLton, ML Kit and HaMLet rejects it.
Error messages are rather confusing to me. The clearest one to my eyes, is the one from HaMLet, which complains about “illegal expression within recursive value binding”.
(* A datatype to pass recursion as result and to arguments. *)
datatype 'a process = Chain of ('a -> 'a process)
(* A controlling iterator, where the item handler is
* of type `'a -> 'a process`, so that while handling an item,
* it's also able to return the next handler to be used, making
* the handler less passive. *)
val rec iter =
fn process: int -> int process =>
fn first: int =>
fn last: int =>
let
val rec step =
fn (i: int, Chain process) (* -> unit *) =>
if i < first then ()
else if i = last then (process i; ())
else if i > last then ()
else
let val Chain process = process i
in step (i + 1, Chain process)
end
in step (first, Chain process)
end
(* An attempt to set‑up a syntax to make use of the `Chain` constructor,
* a bit more convenient and readable. *)
val chain: unit * ('a -> 'a process) -> 'a process =
fn (a, b) => (a; Chain b)
infixr 0 THEN
val op THEN = chain
(* A test of this syntax:
* - OK with Poly/ML, which displays “0-2|4-6|8-10|12-14|16-18|20”.
* - fails with MLton, which complains about a syntax error on line #44.
* - fails with ML Kit, which complains about a syntax error on line #51.
* - fails with HaMLet, which complains about a syntax error on line #45.
* The clearest (while not helpful to me) message comes from HaMLet, which
* says “illegal expression within recursive value binding”. *)
val rec process: int -> int process =
(fn x => print (Int.toString x) THEN
(fn x => print "-" THEN
(fn x => print (Int.toString x) THEN
(fn x => print "|" THEN
process))))
val () = iter process 0 20
val () = print "\n"
(* Here is the same without the `THEN` operator. This one works with
* all of Poly/ML, MLton, ML Kit and HaMLet. *)
val rec process =
fn x =>
(print (Int.toString x);
Chain (fn x => (print "-";
Chain (fn x => (print (Int.toString x);
Chain (fn x => (print "|";
Chain process)))))))
val () = iter process 0 20
val () = print "\n"
(* SML implementations version notes:
* - MLton, is the last version, built just yesterday
* - Poly/ML is Poly/ML 5.5.2
* - ML Kit is MLKit 4.3.7
* - HaMLet is HaMLet 2.0.0 *)
Update
I could work around the issue, but still don't understand it. If I remove the outermost parentheses, then it validates:
val rec process: int -> int process =
fn x => print (Int.toString x) THEN
(fn x => print "-" THEN
(fn x => print (Int.toString x) THEN
(fn x => print "|" THEN
process)))
Instead of:
val rec process: int -> int process =
(fn x => print (Int.toString x) THEN
(fn x => print "-" THEN
(fn x => print (Int.toString x) THEN
(fn x => print "|" THEN
process))))
But why is this so? An SML syntax subtlety? What's its rational?
It's just an over-restrictive sentence in the language definition, which says:
For each value binding "pat = exp" within rec, exp must be of the form "fn match".
Strictly speaking, that doesn't allow any parentheses. In practice, that's rarely a problem, because you almost always use the fun declaration syntax anyway.

SML Function Argument Pattern Matching

I am using pattern matching on argument passed to a function. The method works fine for "first level" matching so to say but any attempt to go deeper gives the error "stdIn:282.5-291.77 Error: match redundant"
example
fun nnf T = T
| nnf F = F
| nnf (LETTER(x)) = (LETTER(x))
| nnf (NEG(x)) = (NEG(nnf x))
| nnf (AND(x,y)) = (AND(nnf x, nnf y))
| nnf (OR(x,y)) = (OR(nnf x, nnf y))
| nnf (IMP(x,y)) = (OR(NEG(nnf x),(nnf y)))
| nnf (NEG(NEG(LETTER(x)))) = (LETTER(x))
| nnf (NEG(AND(LETTER(x),LETTER(y)))) = (OR(NEG(LETTER(x)),NEG(LETTER(y))))
| nnf (NEG(OR(LETTER(x),LETTER(y)))) = (AND(NEG(LETTER(x)),NEG(LETTER(y))));
val nnf = fn : prop -> prop
the error i get is
stdIn:282.5-291.77 Error: match redundant
T => ...
F => ...
LETTER x => ...
NEG x => ...
AND (x,y) => ...
OR (x,y) => ...
IMP (x,y) => ...
--> NEG (NEG (LETTER x)) => ...
--> NEG (AND (LETTER x,LETTER y)) => ...
--> NEG (OR (LETTER x,LETTER y)) => ...
so SML is saying that the last 3 clauses in the function definition are the same since they all begin with "(NEG(..." even though what follows is different.
how do i overcome this ?
The case NEG(x) already covers any possible case involving outermost NEG, so the others are never reached. Depending on what you actually want to achieve, either remove that case, or move it after the more specific ones (cases are tried in order).

Resources