How to pass string variables as arguments in function in OCaml? - ocaml

I wrote a simple code for a function which takes a string and return its length:
let fun x = String.length x;;
But it's showing syntax error. Why?
If I just write String.length x;; it's fine but what's wrong in my function declaration?
How to pass string variable as argument to function in OCaml?

fun is a reserved keyword in OCaml. You can choose another name that's not a keyword and the function will work. Here's a list of reserved keywords in OCaml: https://caml.inria.fr/pub/docs/manual-ocaml/manual071.html

You are mixing different syntaxes here:
LET <ident> <ident>* = <expr>
FUN <ident>* -> <expr>
The "let" must be followed by the name of the function you want to create and "fun", being a reserved keyword, is not a valid name for the function. It's a keyword and not an identifyer so the syntax parser gives you an error.

Related

Is is possible to use operators under literals?

Suppose I have the following function
fx(label, text) = match(Regex("\\W*\\Q$label\\E\\s*(.*)"), text).captures[]
text1 = "IAREA aoi/IA_1.ias"
The result of the first function call
fx("IAREA (?!FILE)", text1)
is expected (probably with a wrong reason), because string "IAREA" is not followed by "FILE" in test1.
But the result of the second function call
fx("IAREA (?!MMM)", text1)
is not expected: Because "IAREA" in "text1" is NOT followed by "MMM", this function call should return aoi/IA_1.ias, but it returns nothing.
I'm wondering: Is it possible to achieve this by changing the label argument, not by changing the function body?
Since you pass a regex pattern to the regex constructor, you needn't use the \Q and \E operators since all characters in between the two operators are treated as literal symbols.
You need to fix as follows:
Regex("\\W*$label\\s*(.*)")

How to replace the match with a function in a regex expression in Python

I'm trying to get a better understanding of how lambda functions and regex matches work in Python. For this purpose I'm replacing a lambda with a named function.
Even though I've found a way to make it work, I'm not able to understand why it works.
The lambda/regex I'm working on are the one mentioned in the following posts:
How to replace multiple substrings of a string?
Python - Replace regular expression match with a matching pair value
This is the main piece of code:
import re
# define desired replacements here
rep = {"condition1": "", "condition2": "text"}
text = "(condition1) and --condition2--"
# use these three lines to do the replacement
rep = dict((re.escape(k), v) for k, v in rep.items())
pattern = re.compile("|".join(rep.keys()))
output = pattern.sub(lambda m: rep[re.escape(m.group(0))], text)
print(output)
>>> '() and --text--'
If I replace the lambda function with:
def replace_conditions(match, rep):
return rep[re.escape(match.group(0))]
output = pattern.sub(replace_conditions(m, rep), text)
I get the following exception:
NameError: name 'm' is not defined
And I'm able to make it work only using this syntax:
def replace_conditions(match, rep=rep):
return rep[re.escape(match.group(0))]
output = pattern.sub(replace_conditions, line)
NOTE: I had to pre-assign a value to the second argument "rep" and use the function's name without actually calling it.
I can't understand why the match returned by the regex expression is properly passed on to the function if called with no arguments, while it's not passed to its first argument when called with the usual syntax.
I can't understand why the match returned by the regex expression is properly passed on to the function if called with no arguments
That's not what's happening. pattern.sub(replace_conditions, line) doesn't call the replace_conditions function, it just passes it on.
From the docs for:
re.sub(pattern, repl, string, count=0, flags=0)
which is the same as:
pattern.sub(repl, string)
If repl is a function, it is called for every non-overlapping occurrence of pattern. The function takes a single match object argument, and returns the replacement string.

Ocaml record matching

Given a basic record
type t = {a:string;b:string;c:string}
why does this code compile
let f t = match t with
{a;b;_} -> a
but this
let f t = match t with
{_;b;c} -> b
and
let f t = match t with
{a;_;c} -> c
does not? I'm asking this out of curiosity thus the obvious useless code examples.
The optional _ field must be the last field. This is documented as a language extension in Section 7.2
Here's the production for reference:
pattern ::= ...
∣ '{' field ['=' pattern] { ';' field ['=' pattern] } [';' '_' ] [';'] '}'
Because the latter two examples are syntactically incorrect. The syntax allows you to terminate your field name pattern with the underscore to notify the compiler that you're aware, that there are more fields than you are trying to match. It is used to suppress a warning (that is disabled by default). Here is what the OCaml manual says about it:
Optionally, a record pattern can be terminated by ; _ to convey the fact that not all fields of the record type are listed in the record pattern and that it is intentional. By default, the compiler ignores the ; _ annotation. If warning 9 is turned on, the compiler will warn when a record pattern fails to list all fields of the corresponding record type and is not terminated by ; _. Continuing the point example above,
If you want to match to a name without binding it to a variable, then you should use the following syntax:
{a=_; b; c}
E.g.,
let {a=_; b; c} = {a="hello"; c="cruel"; b="world"};;
val b : string = world
val c : string = cruel
To add to the answers by Jeffrey Scofield and ivg, what the erroneous examples are trying to achieve can in fact be achieved by using a different order of fields. Like so:
let f t = match t with
{b;c;_} -> b

How to get the integer part of a string in OCaml?

My string has the format of A3, A5, A38... and I'm only interested in the integer part of it.
I want something like:
let getIntofString s = match s with
"A1" -> 1
| ..
How do I do it?
Take a look at string_of_int from the initially opened module and at sub from the standard library's String module. That should get you started.
The Scanf module allows for some simple pattern matching where no elaborate parsing is needed.
Example:
let identity x = x
let parseAInt s =
Scanf.sscanf s "A%u" identity
Here, Scanf.sscanf takes as its first argument the input string, as its second argument the pattern to be matched (%u denoting an unsigned integer), and as its third argument a function that converts the parsed results into the type needed. As we don't need such a conversion in this case, the identity function suffices here.
Note that you may have to handle exceptions (Scanf.Scan_failure for a pattern mismatch, End_of_file for running out of characters to read, or Failure for being unable to convert a string to a number) if you cannot guarantee that the input to this function actually matches the pattern (for example, because it was supplied by a user).
You have to use sub, length and int_of_string.
open String
let getIntofString s =
let l=length s in
let si=sub s 1 (l-1) in
int_of_string si
;;
Test
# getIntofString "A18";;
- : int = 18
# getIntofString "A";;
Exception: Failure "int_of_string".
# getIntofString "";;
Exception: Invalid_argument "String.sub / Bytes.sub".

"Can't let qualified name" when using clojure.core.match

I'm using clojure.core.match and seeing the following error:
Can't let qualified name
My code resembles:
(match [msg-type]
[MsgType/TYPE_1] (do-type-1-thing)
[MsgType/TYPE_2] (do-type-2-thing))
Where MsgType/TYPE_1 comes from a Java class:
public class MsgType {
public static final String TYPE_1 = "1";
public static final String TYPE_2 = "2";
}
What does this error mean, and how can I work around it?
The problem seems related to macro name binding, though I don't understand it deeply as I'm quite new to macros.
Originally I hoped using case rather than match would prove a viable workaround:
(case msg-type
MsgType/TYPE_1 (do-type-1-thing)
MsgType/TYPE_2 (do-type-2-thing))
However the above doesn't work. case matches on the symbol MsgType/TYPE_n, not the evaluation of that symbol.
The best I've found so far is to convert the value coming in to a keyword and match that way:
(def type->keyword
{MsgType/TYPE_1 :type-1
MsgType/TYPE_2 :type-2})
(case (type->keyword msg-type)
:type-1 (do-type-1-thing)
:type-2 (do-type-2-thing))
In general, pattern matching is not the right tool for comparing one variable with another. Patterns are supposed to be either literals such as 1 or :a, destructuring expressions or variables to be bound. So, for example, take this expression:
(let [a 1
b 2]
(match [2]
[a] "It matched A"
[b] "It matched B"))
You might expect it to yield "It matched B" since the variable b is equal to 2, but in fact it will bind the value 2 to a new variable named a and yield "It matched A".
I think you're looking for condp =. It's basically what you wish case would be.
(condp = msg-type
MsgType/TYPE_1 (do-type-1-thing)
MsgType/TYPE_2 (do-type-2-thing))