I've been trying to create a code in F# that can read text via another file, however I keep seeing a
The block following this 'let' is unfinished. Every code block is an expression and must have a result
on the
let a = line.Split delim
,I looked it up and thought it was an indentation error but that didn't fix that. Any advice?
[<EntryPoint>]
let main argv =
let delim = ','
use stream = new StreamReader #"final.txt"
let line = stream.Readline()
let a = line.Split delim
|>Seq.map System.Int32.Parse
|>Seq.toArray
printfn "Orignal numbers: %A" a
printfn "Ordered numbers: %A" (oddEven a)
0 // return an integer exit code
You're missing indentation (and misspelled a thing or two). Anything that you want to be part of a let block has to be indented one level. Here's your code properly formatted:
[<EntryPoint>]
let main argv =
let delim = ','
use stream = new StreamReader #"final.txt"
let line = stream.ReadLine()
let a =
line.Split delim
|> Seq.map System.Int32.Parse
|> Seq.toArray
printfn "Orignal numbers: %A" a
printfn "Ordered numbers: %A" (oddEven a)
0 // return an integer exit code
Related
I have a problem where during the parsing of a stream I get to point where the next N characters need to be parsed by applying a specfic parser multiple times (in sequence).
(stripped down toy) Example:
17<tag><anothertag><a42...
^
|- I'm here
Let's say the 17 indicates that the next N=17 characters make up tags, so I need to repetetively apply my "tagParser" but stop after 17 chars and not consume the rest even if it looks like a tag because that has a different meaning and will be parsed by another parser.
I cannot use many or many1 because that would eat the stream beyond those N characters.
Nor can I use parray because I do not know how many successful applications of that parser are there within the N characters.
I was looking into manyMinMaxSatisfy but could not figure out how to make use of it in this case.
Is there a way to cut N chars of a stream and feed them to some parser? Or is there a way to invoke many applications but up to N chars?
Thanks.
You can use getPosition to make sure you don't go past the specified number of characters. I threw this together (using F# 6) and it seems to work, although simpler/faster solutions may be possible:
let manyLimit nChars p =
parse {
let! startPos = getPosition
let rec loop values =
parse {
let! curPos = getPosition
let nRemain = (startPos.Index + nChars) - curPos.Index
if nRemain = 0 then
return values
elif nRemain > 0 then
let! value = p
return! loop (value :: values)
else
return! fail $"limit exceeded by {-nRemain} chars"
}
let! values = loop []
return values |> List.rev
}
Test code:
let ptag =
between
(skipChar '<')
(skipChar '>')
(manySatisfy (fun c -> c <> '>'))
let parser =
parse {
let! nChars = pint64
let! tags = manyLimit nChars ptag
let! rest = restOfLine true
return tags, rest
}
run parser "17<tag><anothertag><a42..."
|> printfn "%A"
Output is:
Success: (["tag"; "anothertag"], "<a42...")
Quite low-level parser, that operates on raw Reply objects. It reads count of chars, creates substring to feed to tags parser and consumes rest. There's should be an easier way, but I don't have much experience with FParsec
open FParsec
type Tag = Tag of string
let pTag = // parses tag string and constructs 'Tag' object
skipChar '<' >>. many1Satisfy isLetter .>> skipChar '>'
|>> Tag
let pCountPrefixedTags stream =
let count = pint32 stream // read chars count
if count.Status = Ok then
let count = count.Result
// take exactly 'count' chars
let tags = manyMinMaxSatisfy count count (fun _ -> true) stream
if tags.Status = Ok then
// parse substring with tags
let res = run (many1 pTag) tags.Result
match res with
| Success (res, _, _) -> Reply(res)
| Failure (_, error, _) -> Reply(ReplyStatus.Error, error.Messages)
else
Reply(tags.Status, tags.Error)
else
Reply(count.Status, count.Error)
let consumeStream =
many1Satisfy (fun _ -> true)
run (pCountPrefixedTags .>>. consumeStream) "17<tag><anothertag><notTag..."
|> printfn "%A" // Success: ([Tag "tag"; Tag "anothertag"], "<notTag...")
You also can do this without going down to stream level.
open FParsec
let ptag =
between
(skipChar '<')
(skipChar '>')
(manySatisfy (fun c -> c <> '>'))
let tagsFromChars (l: char[]) =
let s = new System.String(l)
match run (many ptag) s with
| Success(result, _, _) -> result
| Failure(errorMsg, _, _) -> []
let parser =
parse {
let! nChars = pint32
let! tags = parray nChars anyChar |>> tagsFromChars
let! rest = restOfLine true
return tags, rest
}
run parser "17<tag><anothertag><a42..."
|> printfn "%A"
So far, I have pretty much things set but that dumb printfn is still not working.
open System
[<EntryPoint>]
let main argv =
let n = Console.ReadLine() |> int
let nums = seq { for i in 1..n -> Console.ReadLine() |> int }
printfn "%d" (Seq.sum nums)
0
The answer from Joseph explains what is wrong with your code.
If you wanted to do this in a more F# way, then you'd probably want to eliminate the mutation altogether. One reasonably nice way of doing this would be to use sequence expressions to construct a sequence of all the numbers that you're reading from the console and then use Seq.sum to calculate the sum:
[<EntryPoint>]
let main argv =
let n = Console.ReadLine() |> int
let nums = seq { for i in 1..n -> Console.ReadLine() |> int }
printfn "%d" (Seq.sum nums)
0
Two things I noticed, you need to end the program with 0, that is the exit code.
Second thing is the equals sign in FSharp isn't used for updating values, F# uses the <- operator instead. Here is your program with the updated changes.
open System
[<EntryPoint>]
let main argv =
let mutable sum = 0
let n = Console.ReadLine() |> int
for i in 1..n do
let mutable r = Console.ReadLine() |> int
sum <- sum + r;
printfn "%d" sum
0
I am trying to wrap a call to sprintf function. Here's my attempt:
let p format args = "That was: " + (sprintf format args)
let a = "a"
let b = "b"
let z1 = p "A %s has invalid b" a
This seems to work, output is
val p : format:Printf.StringFormat<('a -> string)> -> args:'a -> string
val a : string = "a"
val b : string = "b"
val z1 : string = "That was: A a has invalid b"
But it wouldn't work with more than one arg:
let z2 = p "A %s has invalid b %A" a b
I get compile-time error:
let z2 = p "A %s has invalid b %A" a b;;
---------^^^^^^^^^^^^^^^^^^^^^^^^^^^
stdin(7,10): error FS0003: This value is not a function and cannot be applied
How can I create a single function which would work with any number of args?
UPD. Tomas has suggested to use
let p format = Printf.kprintf (fun s -> "This was: " + s) format
It works indeed. Here's an example
let p format = Printf.kprintf (fun s -> "This was: " + s) format
let a = p "something like %d" 123
// val p : format:Printf.StringFormat<'a,string> -> 'a
// val a : string = "This was: something like 123"
But the thing is that main purpose of my function is to do some work except for formatring, so I tried to use the suggested code as follows
let q format =
let z = p format // p is defined as suggested
printf z // Some work with formatted string
let z = q "something like %d" 123
And it doesn't work again:
let z = q "something like %d" 123;;
----------^^^^^^^^^^^^^^^^^^^
stdin(30,15): error FS0001: The type ''c -> string' is not compatible with the type 'Printf.TextWriterFormat<('a -> 'b)>'
How could I fix it?
For this to work, you need to use currying - your function p needs to take the format and return a function returned by one of the printf functions (which can then be a function taking one or more arguments).
This cannot be done using sprintf (because then you would have to propagate the arguments explicitly. However, you can use kprintf which takes a continuation as the first argument::
let p format = Printf.kprintf (fun s -> "This was: " + s) format
The continuation is called with the formatted string and so you can do whatever you need with the resulting string before returning.
EDIT: To answer your extended question, the trick is to put all the additional work into the continuation:
let q format =
let cont z =
// Some work with formatted string
printf "%s" z
Printf.kprintf cont format
I have the following program that runs. It takes a line of text and splits it into two parts, the first is an identifier and the second is the remainder of the line. My parser for the identifier (factID) takes any string of characters as the identifier, which is not (quite) what I want. What I want is a parser that only succeeds when it encounters two consecutive upper case letters. So for example "AA" should succeed while "A", "A1" or "AAA" should not.
What I can't figure out is how construct a parser that looks for a fixed length token. I thought perhaps CharParsers.next2CharsSatisfy might be the function I am looking for, but I can't figure out how to properly use it.
open FParsec
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
let ws = spaces
let str_ws s = pstring s .>> ws
type StringConstant = StringConstant of string * string
let factID =
let isIdentifierFirstChar c = isLetter c
let isIdentifierChar c = isLetter c
many1Satisfy2L isIdentifierFirstChar isIdentifierChar "factID"
let factText =
let isG c = isLetter c || isDigit c || c = ' ' || c = '.'
manySatisfy isG
let factParse = pipe3 factID (str_ws " ") factText
(fun id _ str -> StringConstant(id, str))
[<EntryPoint>]
let main argv =
test factParse "AA This is some text." // This should pass
test factParse "A1 This is some text." // This should fail
test factParse "AAA This is some text." // This passes but I want it to fail
0 // return an integer exit code
I think this would do it
let pFactID = manyMinMaxSatisfy 2 2 Char.IsUpper
Hi everbody I am doing a project with F# but I get this error when ı use let num= line for the following code . I'm new at F# so I can not solve the problem. My code should do this things. User enter a number and calculate the fibonacci but if user enter not a number throw exception
open System
let rec fib n =
match n with
|0->0
|1->1
|2->1
|n->fib(n-1)+fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i));;
let control = true
while control do
try
printfn "Enter a Number:"
let num:int = Convert.ToInt32(stdin.ReadLine())
with
| :? System.FormatException->printfn "Number Format Exception";
let listFibonacci = [for i in 0 .. num-1->fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
control<-false
Console.ReadKey(true)
exit 0;;
I'm not an F# expert but I can see 3 problems with the code you posted.
1) As Lasse V Karlsen commented - f# uses the 'offside' rule so your 'fib' expression needs the body indented in. If you are running this in the Visual Studio Shell it should warn you of this by putting a blue squiggly line under the appropriate code.
2) Both 'control' and 'num' are mutable values so need to be declared explicitly as such.
f# is a functional language so by default any expressions are immutable i.e they are not allowed to change state after they have been declared.
In f#, saying 'let n = expr' does not mean 'assign the value of expr to n' like you would in say c# or c++. Instead it means 'n fundamentally is expr' and will be forever much like a mathematical equation.
So if you want to update the value of a variable you use the special '<-' notation which is the equivalent of 'assign the value on rhs to the lhs' and you need to declare that variable as mutable i.e 'this value can be changed later'
So I think both num and control need to be declared at the top of the loop as
let mutable control = false
let mutable num = 0 // or whatever you want the initial value of num to be
As a side note you don't have to explicitly declare num as an int ( you can if you want ) but f# will infer the type for you
If I understand your code correctly, you want to keep asking for input number n until a valid number is given and print fibonacci numbers up to n. In this case, you'd better move the calculation and printing inside the try block. Here's an updated version with formatting.
open System
let rec fib n =
match n with
|0->0
|1->1
|2->1
|n->fib(n-1)+fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i))
let mutable control = true //you forgot to add the 'mutable' keyword
while control do
try
printfn "Enter a Number:"
let num:int = Convert.ToInt32(stdin.ReadLine())
let listFibonacci = [for i in 0 .. num-1 -> fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
control <- false
with
| :? System.FormatException -> printfn "Number Format Exception"
//add the ignore statement to drop the resulting ConsoleKeyInfo struct
//or the compiler will complain about an unused value floating around.
Console.ReadKey(true) |> ignore
// exit 0 (* Exit isn't necessary *)
Instead of using an imperative style number entry routine and relying on exceptions for control flow, here's a recursive getNumberFromConsole function you could use as well:
open System
let rec fib n =
match n with
| 0 -> 0
| 1 | 2 -> 1
| n -> fib(n-1) + fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i))
//alternative number input, using recursion
let rec getNumberFromConsole() =
match Int32.TryParse(stdin.ReadLine()) with
| (true, value) -> value
| (false, _) -> printfn "Please enter a valid number"
getNumberFromConsole()
printfn "Enter a Number:"
let num = getNumberFromConsole()
let listFibonacci = [for i in 0 .. num-1 -> fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
Console.ReadKey(true) |> ignore
P.S. Thanks for showing me stdin. I never knew it existed. Now I can write some interactive scripts.