do block with flower brackets in ghci throws error - haskell

I have a code that works with print inside do block as,
do { print ([(n, 2^n) | n <- [0..19]]) }
Then i tried a much simpler version to print a variable value,
do { let a = 1; print (a) }
It throws error as parse error on input }
What else, i tried with no success ---
ghci> let a = 1; print (a)
And
ghci> :{
| let a = 1;
| print (a)
| :}

Once you start a let statement, the rest of the line is considered to be additional let assignments. Consider this error message:
ghci> do print 1; let c = 2; d = 3
<interactive>:3:13:
The last statement in a 'do' block must be an expression
let c = 2
d = 3
Note that the let keyword is not needed for d = 3.
To add a monadic statement after a let you'll need to put it on a separate line (with the correct indentation):
ghci> :{
| do print 1; let a = 2; b = 3
| print b
| :}
1
3
AFAIK, there is no way to put a monadic statement after a let on the same line.

Related

How find integer in text

Help me figure out how to work with text
i have a string like: "word1 number: word2" for example : "result 0: Good" or "result 299: Bad"
i need print Undefined/Low or High
When string is null , print Undefined
When number 0-15, print Low
When number >15, print High
type GetResponse =
{
MyData: string voption
ErrorMessage: string voption }
val result: Result<GetResponse, MyError>
and then i try:
MyData =
match result with
| Ok value ->
if (value.Messages = null) then
ValueSome "result: Undefined"
else
let result =
value.Messages.FirstOrDefault(
(fun x -> x.ToUpperInvariant().Contains("result")),
"Undefined"
)
if (result <> "Undefined") then
ValueSome result
else
errors.Add("We don't have any result")
ValueNone
| Error err ->
errors.Add(err.ToErrorString)
ValueNone
ErrorMessage =
if errors.Any() then
(errors |> String.concat ", " |> ValueSome)
else
ValueNone
but i dont know gow check in string number and maybe there is some way print this without a billion if?
Parsing gets complex very quickly. I recommend using FParsec to simplify the logic and avoid errors. A basic parser that seems to meet your needs:
open System
open FParsec
let parseWord =
manySatisfy Char.IsLetter
let parseValue =
parseWord // parse any word (e.g. "result")
>>. spaces1 // skip whitespace
>>. puint32 // parse an unsigned integer value
.>> skipChar ':' // skip colon character
.>> spaces // skip whitespace
.>> parseWord // parse any word (e.g. "Good")
You can then use it like this:
type ParserResult = Undefined | Low | High
let parse str =
if isNull str then Result.Ok Undefined
else
match run parseValue str with
| Success (num, _ , _) ->
if num <= 15u then Result.Ok Low
else Result.Ok High
| Failure (errorMsg, _, _) ->
Result.Error errorMsg
parse null |> printfn "%A" // Ok Undefined
parse "result 0: Good" |> printfn "%A" // Ok Low
parse "result 299: Bad" |> printfn "%A" // Ok High
parse "invalid input" |> printfn "%A" // Error "Error in Ln: 1 Col: 9 ... Expecting: integer number"
There's definitely a learning curve with FParsec, but I think it's worth adding to your toolbelt.
I agree with Brian that parsing can become quite tricky very quickly. However if you have some well established format of the input and you're not very much into writing complex parsers, good old regular expressions can be of service ;)
Here is my take on the problem - please note that it has plenty of room to improve, this is just a proof of concept:
open System.Text.RegularExpressions
let test1 = "result 0: Good"
let test2 = "result 299: Bad"
let test3 = "some other text"
type ParserResult =
| Undefined
| Low of int
| High of int
let (|ValidNumber|_|) s =
//https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=net-6.0
let rx = new Regex("(\w\s+)(\d+)\:(\s+\w)")
let matches = rx.Matches(s)
if matches.Count > 0 then
let groups = matches.[0].Groups |> Seq.toList
match groups with
| [_; _; a; _] -> Some (int a.Value)
| _ -> None
else
None
let parseMyString str =
match str with
| ValidNumber n when n < 16 -> Low n
| ValidNumber n -> High n
| _ -> Undefined
//let r = parseMyString test1
printfn "%A" (parseMyString test1)
printfn "%A" (parseMyString test2)
printfn "%A" (parseMyString test3)
The active pattern ValidNumber returns the Some number if a match of the input string is found, otherwise it returns None. The parseMyString function uses the pattern and guards to initialise the final ParserOutput value.

how to return a scarlar with let as method

I am trying to compare if an array is a subset of other and use it in another query. I could get the comparision method working. However, if I use the compare method in another query I get an error saying "Left and right side of the relational operator must be scalars" This hints that the comparearrays is not reutrning a scalar. Any ideas?
let x = parsejson('["a", "b", "c"]');
let y = parsejson('["a", "b", "c"]');
let z = parsejson('["b","a"]');
let comparearrays = (arr1:dynamic, arr2:dynamic)
{
let arr1Length = arraylength(arr1);
let total =
range s from 0 to arr1Length-1 step 1
| project dat = iff(arr1[s] in (arr2), true , false)
| where dat == true
| count;
total | extend isEqual= iff(Count == arr1Length,'true','false') | project
tostring(isEqual)
};
//comparearrays(z, x)
datatable (i:int) [4] | project i | where comparearrays(x,y) == 'true'
You are correct in your understanding - the current implementation returns a table with a single row and single column, but have no fear - toscalar to the rescue:
let x = parsejson('["a", "b", "c"]');
let y = parsejson('["a", "b", "c"]');
let z = parsejson('["b","a"]');
let comparearrays = (arr1:dynamic, arr2:dynamic)
{
let arr1Length = arraylength(arr1);
let result =
range s from 0 to arr1Length-1 step 1
| project dat = iff(arr1[s] in (arr2), true , false)
| where dat == true
| count
| extend isEqual = iff(Count == arr1Length,'true','false')
| project tostring(isEqual);
toscalar(result)
};
//comparearrays(z, x)
datatable (i:int) [4] | project i | where comparearrays(x,y) == 'true'
You do have a bug in the comparearrays functions, since comparearrays(z, x) returns true which is not correct....

reading integers from a string

I want to read a line from a file, initialize an array from that line and then display the integers.
Why is is not reading the five integers in the line? I want to get output 1 2 3 4 5, i have 1 1 1 1 1
open Array;;
open Scanf;;
let print_ints file_name =
let file = open_in file_name in
let s = input_line(file) in
let n = ref 5 in
let arr = Array.init !n (fun i -> if i < !n then sscanf s "%d" (fun a -> a) else 0) in
let i = ref 0 in
while !i < !n do
print_int (Array.get arr !i);
print_string " ";
i := !i + 1;
done;;
print_ints "string_ints.txt";;
My file is just: 1 2 3 4 5
You might want to try the following approach. Split your string into a list of substrings representing numbers. This answer describes one way of doing so. Then use the resulting function in your print_ints function.
let ints_of_string s =
List.map int_of_string (Str.split (Str.regexp " +") s)
let print_ints file_name =
let file = open_in file_name in
let s = input_line file in
let ints = ints_of_string s in
List.iter (fun i -> print_int i; print_char ' ') ints;
close_in file
let _ = print_ints "string_ints.txt"
When compiling, pass str.cma or str.cmxa as an argument (see this answer for details on compilation):
$ ocamlc str.cma print_ints.ml
Another alternative would be using the Scanf.bscanf function -- this question, contains an example (use with caution).
The Scanf.sscanf function may not be particularly suitable for this task.
An excerpt from the OCaml manual:
the scanf facility is not intended for heavy duty lexical analysis and parsing. If it appears not expressive enough for your needs, several alternative exists: regular expressions (module Str), stream parsers, ocamllex-generated lexers, ocamlyacc-generated parsers
There is though a way to parse a string of ints using Scanf.sscanf (which I wouldn't recommend):
let rec int_list_of_string s =
try
Scanf.sscanf s
"%d %[0-9-+ ]"
(fun n rest_str -> n :: int_list_of_string rest_str)
with
| End_of_file | Scanf.Scan_failure _ -> []
The trick here is to represent the input string s as a part which is going to be parsed into a an integer (%d) and the rest of the string using the range format: %[0-9-+ ]", which will match the rest of the string, containing only decimal digits 0-9, the - and + signs, and whitespace .

Swift REPL Unexpected Behaviour

If I use the following code in Swift repl, I get unexpected results:
1> func addA(s: String)->String {
2. return s + "a"
3. }
4.
5. func addB(s: String)->String {
6. return s + "b"
7. }
8>
9> println(addA(""))
a
10> println(addB(""))
b
11> println(addA(addB("")))
ba
12> let p = addA(addB(""))
p: ((String)) = {
_core = {
_baseAddress = 0x0000000100500060
_countAndFlags = 2
_owner = (instance_type = Builtin.RawPointer = 0x0000000100500040)
}
}
13> println(p)
ba
14> let q = "a" + "b"
q: String = "ab"
why does declaring p produce this behaviour, while declaring q does not?
All that's happening here is that the REPL is letting you look inside Swift at some of the underlying efficiencies. p is stored as some sort of function composition. When evaluation is needed, it is evaluated. If you didn't want to see the sausage being made, you should not have entered the sausage factory.

Let bindings in do notation without layout require "in"?

In Haskell you can say
main = do
let x = 5
print x
and this will not compile:
main = do
let x = 5
in print x
But if I am using explicit layout, this does not compile:
main = do {
let x = 5;
print x;
}
but this works:
main = do {
let x = 5
in print x;
}
Am I right? Is there anyplace I can read more about explicit layout and do and let notation? Section 3.14 of the Haskell 98 report seems to me to suggest that my third example should work, as it says I can write
do { let DECLS; stmts }
and it translates to
let DECLS in do { stmts }
The normative answer to your question can be found in the Haskell report's description of the layout rule.
Briefly, you need to place a semicolon between your let block and the next statement of the do block. That semicolon needs to lie outside of the let block. If you don't use layout for the let block, that's easy, just say:
let {x = 5};
However, if you do use layout for the let block, then the only way to close the let block is to start a line in a column before the column of x. So that means you'd have to write something like this:
main = do {
let x = 5
; print x;
}
Oh, and for your other example, again with layout a semicolon is getting inserted before the in, so your code desugars to:
main = do {
let {x = 5
};
in print x
}

Resources