let Trans(DirPath:string) =
if ( numOfVmFiles(DirPath) > 1) then //if there are more than 1 vm files in the directory
Init("")
let VmFiles = ListOfVmFiles(DirPath)
for VmFile in VmFiles do // for each vm file
ReadFile(VmFile)
I got this error:
Error Block following this 'let' is unfinished. Expect an expression.
what should I write?thznk u
The existing answers give you good hints on how to write your code better. You said you are getting an error:
Block following this 'let' is unfinished. Expect an expression.
This typically indicates missing = or wrong indentation after the end of your function (or some easy to miss syntax error like that). In the snippet you posted, all syntax looks good to me, so I suspect there is something wrong elsewhere too. The following gives no errors:
let numOfVmFiles a = 0
let Init a = ()
let ListOfVmFiles a = []
let ReadFile a = ()
let Trans(DirPath:string) =
if ( numOfVmFiles(DirPath) > 1) then
Init("")
let VmFiles = ListOfVmFiles(DirPath)
for VmFile in VmFiles do // for each vm file
ReadFile(VmFile)
You get two warnings - because variable names should be camelCase rather than PascalCase, but no error. As others said, you should probably make Init and ReadFile return something and then you need to collect the results (to make your code more functional), but that's a separate problem.
The problem is that the function does not return a value. Functions must always return a value. If there is nothing to return, return unit. You can return unit as ().
I made some possibly incorrect assumptions here but I tried to make clear what they were. On the trans function I also show how you can specify the return type. It is usually best to let the compiler infer the type until it cannot. Hover over the functions and see what the compiler is telling you about the types. string -> int -> string list means a function takes a string and an int and returns a list of strings.
let init dirName = () //unit is returned... kind of like void but is actually a return value
let listOfVmFiles dirName = ["some";"files"] // list of string
let readFile path = "content of file" //string
let trans(dirPath:string) : string list = // takes a string and returns a list of string represented as string-> string list
let vmFiles = listOfVmFiles(dirPath) // get files from path
if(vmFiles.Length > 1) then init("") // init if more than 1 file
List.map readFile vmFiles // return a list of the content of the files
If a function is performing a side-effect and does not return something then it can be done like so:
let trans(dirPath:string) : unit =
let vmFiles = listOfVmFiles(dirPath)
if(vmFiles.Length > 1) then init("")
List.map readFile vmFiles |> ignore //ignore the result
()
This ignores the result of mapping the readFile function over the list and then returns unit using ().
I recommend fsharp for fun and profit for learning fsharp.
Hope this helps and good luck. Although the syntax seems weird initially stick with it. It's great!
In F# a function returns the value of the last expression it evaluated.
In your particular case it returns unit (), because a for loop returns unit unless its body yields values (in which case you would need to wrap it in a seq).
As mentioned in the comments, this code parses ok- your issue is with an unfinished expression elsewhere in your code.
The rewrite by Devon Buriss is a good example of best practices:
Explicitly declare your function return value in the signature.
ignore function return values if the function is only called for side effects (eg readFile and init("")).
Prefer functional behaviors such as map over imperatives such as for .. do.
As an aside, relying so heavily on side effects is likely to cause you difficulties elsewhere. A more common practice with data crunching is do have a function like readFile return file contents as a seq, and pipe the result to downstream processing:
List.map readFile vmFiles
|> seq.Concat // concatenate the file outputs
|> processContents
Whether or not this is the right thing for you depends on what exactly you intend to do with the contents of each file.
Related
I want to write the following code:
let someAsync () = async {
if 1 > 2 then return true // Error "this expression is expected to have type unit ..."
// I want to place much code here
return false
}
F# for some reason thinks that I need to write it like that:
let someAsync () = async {
if 1 > 2 then return true
else
// Much code here (indented!)
return false
}
In latter case no error message is produced. But in my view both pieces of code are equivalent. Is there any chance I could avoid unnecessary nesting and indentation?
UPD. What I am asking is possible indeed! Please take a look at example, see section Real world example
I will quote the code:
let validateName(arg:string) = imperative {
if (arg = null) then return false // <- HERE IT IS
let idx = arg.IndexOf(" ")
if (idx = -1) then return false // <- HERE IT IS
// ......
return true
}
So, it is possible, the only question is if it is possible to implement somehow in async, via an extension to module or whatever.
I think that situation is described here: Conditional Expressions: if... then...else (F#)
(...) if the type of the then branch is any type other than unit,
there must be an else branch with the same return type.
Your first code does not have else branch, which caused an error.
There is an important difference between the async computation builder and my imperative builder.
In async, you cannot create a useful computation that does not return a value. This means that Async<'T> represents a computation that will eventually produce a value of type 'T. In this case, the async.Zero method has to return unit and has a signature:
async.Zero : unit -> Async<unit>
For imperiatve builder, the type Imperative<'T> represents a computation that may or may not return a value. If you look at the type declaration, it looks as follows:
type Imperative<'T> = unit -> option<'T>
This means that the Zero operation (which is used when you write if without else) can be computation of any type. So, imperative.Zero method returns a computation of any type:
imperative.Zero : unit -> Imperative<'T>
This is a fundamental difference which also explains why you can create if without else branch (because the Zero method can create computation of any type). This is not possible for async, because Zero can only create unit-returning values.
So the two computations have different structures. In particular, "imperative" computations have monoidal structure and async workflows do not. In more details, you can find the explanation in our F# Computation Zoo paper
I sometimes have the need to get the function itself, not the value, of a zero-parameter function in F#, for instance for memoization. I.e., I have this:
let memoize (f: 'a -> 'b) =
let dict = new Dictionary<'a, 'b>()
let memoizedFunc (input: 'a) =
match dict.TryGetValue(input) with
| true, x -> x
| false, _ ->
let answer = f input
dict.Add(input, answer)
answer
memoizedFunc
and this works perfectly, but now I have the following function:
let private getDataSlowOperation =
// implementation
and when I try to memoize that, it gives a type mismatch (essentially the mismatch between the return type of getDataSlowOperation and the 'a type). I can solve this by changing the function as follows:
let private getDataSlowOperation bogus =
// implementation
Now this works, but it seems odd to have to change the function signature to get memoization to work:
let memoGetDataSlowOperation = memoize getDataSlowOperation
I've experimented with inline fun declarations, but this creates, of course, a new anonymous function and the memoization doesn't work with that. Any ideas how to resolve this? Any keyword / operator I've forgotten about?
What you defined is not a function, it's just a value.
In order to define it as a function you can write this:
let private getDataSlowOperation() =
// implementation
UPDATE
To summarize the discussion:
This is the right way to write it as a function, however the code would still not work but that's a different problem.
The code would fail at runtime because () is compiled to null and by using a Dictionary you can't use null for the Key. You can use a Map instead.
John pointed out that memoization for functions without parameters makes no sense, I agree.
Still, if you use a Dictionary for functions with parameters you will run into the same problem with values that are compiled to null, ie: None
I'm a hobbyist programmer (cook by trade) that's currently trying to teach myself F# and functional programming in general.
Anyway, I was fooling around with DeflateStream and wrote the following two functions:
let Compress compressMe =
let ds = new DeflateStream(File.Create("compressed.txt"), CompressionMode.Compress)
File.OpenRead(compressMe).CopyTo(ds)
ds.Close()
let Decompress =
let ds = new DeflateStream(File.OpenRead("compressed.txt"), CompressionMode.Decompress)
ds.CopyTo(File.Create("decompressed.txt"))
ds.Close()
In the body of the main function they are called one right after the other like this:
Compress args.[0]
Decompress
However, if compressed.txt doesn't exist when the program is run Decompress throws a FileNotFoundException which is surprising because the only thing that could throw this is the call to File.OpenRead("compress.txt"). After about an hour I figured out that Decompress was implementing IComparable and was being executed before the call to it in the main function. I found that by changing its definition to let Decompress () = [...] it no longer implemented IComparable and my code executed as it was intended to. Can anyone tell me why F# was infering IComparable and why such and inference would cause the function to execute before the main function marked with [<EntryPoint>]? Also, please forgive the imperitive style of my code, I'm incredibly new at this.
Thanks in adavance.
I'm not entirely sure about the IComparable bit, but the issue you have is that without the parentheses, the compiler is treating Decompress as a value not a function. This would be similar to if you had written.
let compressedName = "compressed.txt"
in that case, compressedName is now a value. Adding the parentheses tells the compiler that this is a function whose code must be called each time the function is rather than a value initialized once (before the entry point) by the code you wrote.
When you write something like
let value =
//some long calculation
[<Entrypoint>]
let main args = ...
The compiler executes the long calculation before main. This is because you probably use the value later in your code. To suppress this, as you found, you need to use let value() = ....
I am not sure where Icomparable is coming from, but this is the key to what is happening.
Note, if you write
let a = ...
let b = ...
The compiler will gurantee a is calculated before b executes.
As others have pointed out, the absence of parentheses in the declaration is significant.
let Decompres = ...
declares a variable of type unit. This type is used to represent "data" (even if this data doesn't encode much information), and it implements IComparable like any other data-oriented type.
let Decompress() = ...
declares a function, and functions in F# are not comparable, probably because there is no universally accepted notion of equality on functions.
I can't see that the "IComparable-ness" of Decompress had anything to do with the exception you got.
i have got several times , trying to implement different functions, the message you see as title. I would like to know if anyone can tell me the general meaning (and reason) of this error message. As i mentioned before, i have got the problem several times and manage to fix it, but still didnt get the exact reason, so i will not post any specific code.
Thank you in advance
The most common case when you may get this error is when you write let binding that is not followed by an expression that calculates the result. In F#, everything is an expression that returns some result, so if you write let a = 10 it is generally not a valid expression. To make it valid, you need to return something:
let foo () =
let a = 10
() // return unit value (which doesn't represent any information)
The only exception where you can write just let a = 10 is a global scope of an F# source file - for example, inside a module declaration or in an F# script file. (This is why the declaration of foo above is valid).
It is difficult to give any advice without seeing your code, but you probably have a let declaration that is not followed by an F# expression.
Out of curiosity, the following example shows that let can really be used inside an expression (where it must return some meaningful result):
let a = 40 + (let a = 1
a + a)
I was playing around with F# (Visual Studio 2010 beta 1), and I wrote a little console script that asked the user to input 2 numbers and an operator and then executed it.
It works fine, apart from a tiny, but annoying thing: sometimes my printfn instructions are ignored. I placed breakpoints in the code to see that's indeed the case.
The code snippet:
let convert (source : string) =
try System.Int32.Parse(source)
with :? System.FormatException ->
printfn "'%s' is not a number!" source;
waitForExitKey();
exit 1
let read =
printfn "Please enter a number.";
System.Console.ReadLine
let num1 : int = read() |> convert // the printfn in the read function is run...
let num2 : int = read() |> convert // ... but here is ignored
This is not the complete source of course, but I think that'll be enough. If you need the complete source just let me know.
So my question is pretty simple: what causes this issue with printfn? Am I doing something wrong?
Thanks in advance,
ShdNx
This page has a partial explanation of what's going on, but the short and sweet version is that F# will execute any value on declaration if it doesn't take parameters.
let read =
printfn "Please enter a number."
System.Console.ReadLine
Since read doesn't take any parameters, its executed immediately on declaration and binds the return value of the function to the identifier read.
Incidentally, your return value happens to be a function with the type (unit -> string). This results because F# automatically curries functions if they aren't passed all of their parameters. ReadLine expects one unit parameter, but since it isn't passed on, you actually bind read to the ReadLine function itself.
The solution is as follows:
let read() = // read takes one unit parameter
printfn "Please enter a number."
System.Console.ReadLine() // pass paramter to ReadLine method
Since read takes one parameter, its re-evaluated each time its called. Additionally, we're passing a parameter to ReadLine, otherwise we'll just return the ReadLine function as a value.
I understand that this can be confusing. In your example, printfn runs earlier than you think. It will actually execute even without the call to read(), i.e., comment out the last two lines and you will still see a message being printed.
I think your intention is something like this:
let read() =
printfn "Please enter a number.";
System.Console.ReadLine()
This will create a "reusable" function instead of binding a function to an identifier as in your original example.
As a sidenote, the use of semi-colons here is optional so you can just write:
let read() =
printfn "Please enter a number."
System.Console.ReadLine()