Now, I try to use Dialyzer and use -spec, -type.
I give the below code to Dialyzer, and I expected Dialyzer to notice "hoge(a) + 1 is invalid", but Dialyzer does not notice.
-spec hoge (X) -> bad when X :: a;
(X) -> number() when X :: number().
hoge(X) when is_number(X) -> 1;
hoge(a) -> bad.
foo() ->
_ = hoge(a) + 1.
But, in another setting,
-spec hoge (X) -> bad when X :: a;
(X) -> string() when X :: number().
hoge(X) when is_number(X) -> "1";
hoge(a) -> bad.
foo() ->
_ = hoge(a) + 1.
Dialyzer tell me this error,
test.erl:12: The call erlang:'+'('bad' | [49,...],1) will never return since it differs in the 1st argument from the success typing arguments: (number(),number())
Why Dialyzer can't notice type-error in first setting.
-spec hoge (X) -> bad when X :: a;
(X) -> number() when X :: number().
This contract(specification) means not "hoge is typed of 'a' -> 'bad' | number() -> number()" but "'a' | number() -> 'bad' | number()"?
Here is a complete module for the first example.
-module(example).
-export([hoge/1, foo/0]).
-spec hoge (X) -> bad when X :: a;
(X) -> number() when X :: number().
hoge(X) when is_number(X) -> 1;
hoge(a) -> bad.
foo() ->
_ = hoge(a) + 1.
The standard answer to "why Dialyzer doesn't catch this error" questions is always "because it is never wrong". Dialyzer never promises to find all errors.
In your problematic example, without the spec, Dialyzer's type inference algorithm indeed produces a union type for all the arguments and all the return values. With the spec, Dialyzer still infers the unions, but should have used the spec to narrow down the return value of the call and then produce an error. This looks like a case of "reduced sensitivity" (but not a bug, per se). You could, in any case, file a bug report.
In your working example, any possible value results in a bad result and Dialyzer's own type inference is enough, even without a spec.
Related
I am using patternmatching within a function as follows :
let rec calculate : Calculation<MyType> -> MyVO -> Calculation<MyType list>=
fun c l ->
fun arrayA arrayC ->
myComputationExpression {
if arrayA.Length<>arrayC.Length then
yield! l
else
match arrayA, arrayC with
| [], [] -> yield! C
| [a], [c] -> yield! calculate a c
| headA :: tailA, headC :: tailC ->
yield! calculateOpenAny headA headC
yield! calculate c l tailA tailC
}
I have the following warning :
Fsc: C:\myfile.fs(17,27): warning FS0025: Incomplete pattern matches on this expression. For example, the value '( _ , [_] )' may indicate a case not covered by the pattern(s).
I quite don't get it because, it should not happen becuse of the first conditionnal statement :
if arrayA.Length<>arrayC.Length then
Is there something I am missing here, or could I overlook the warning?
The problem is that the compiler is not all-seeing. It can prove some things, but it cannot analyse your program fully, paying attention to semantics, like a human could.
In particular, the compiler doesn't know the relationship between the value of property .Length and the shape of the list (i.e. whether it's empty or not). From the compiler's point of view, Length is just a random property, you might as well have compared the results of .ToString() calls.
A better way to go about this would be incorporating different-lengths case in the pattern match:
let rec calculate : Calculation<MyType> -> MyVO -> Calculation<MyType list>=
fun c l ->
fun arrayA arrayC ->
myComputationExpression {
match arrayA, arrayC with
| [], [] -> yield! C
| [a], [c] -> yield! calculate a c
| headA :: tailA, headC :: tailC ->
yield! calculateOpenAny headA headC
yield! calculate c l tailA tailC
| _, _ -> yield! l
}
An additional bonus here would be performance: computing length of a list is actually an O(n) operation, so you'd do better by avoiding it.
On an unrelated note, keep in mind that all of these are equivalent:
fun a -> fun b -> fun c -> ...
fun a -> fun b c -> ...
fun a b -> fun c -> ...
fun a b c -> ...
This is because of how parameters work in F# (and in all of ML family): functions take parameters "one by one", not all at once, at each step returning another function that "expects" the rest of parameters. This is called "currying". Functions in F# are curried by default.
In your case this means that your function could be declared shorter like this:
let rec calculate =
fun c l arrayA arrayC ->
...
Or even shorter like this:
let rec calculate c l arrayA arrayC =
...
I was trying out some erlang code and I am not sure why we have to wrap code in parentheses in some place to work whereas in some other place it work without parentheses as well. Is it due to operator precedence (very unlikely), or due to being statement instead of expression? Erlang newbie here. Please see the examples below.
%% Example from the Programming Erlang book.
-module(lib_misc).
-export([for/3]).
for(Max, Max, F) -> [F(Max)];
for(I, Max, F) -> [F(I)|for(I+1, Max, F)].
I use the above function to generate a list of functions
lib_misc:for(1, 10, fun (X) -> (fun () -> 2*X end) end).
giving something like
[#Fun<erl_eval.20.82930912>,#Fun<erl_eval.20.82930912>,
#Fun<erl_eval.20.82930912>,#Fun<erl_eval.20.82930912>,
#Fun<erl_eval.20.82930912>,#Fun<erl_eval.20.82930912>,
#Fun<erl_eval.20.82930912>,#Fun<erl_eval.20.82930912>,
#Fun<erl_eval.20.82930912>,#Fun<erl_eval.20.82930912>]
Next I tried will calling the function immediately to get the computed result, with three different variation producing the same result and assign it to a variable L.
L = lib_misc:for(1, 10, fun (X) -> (fun () -> 2*X end) end).
lib_misc:for(1, 10, fun (X) -> (fun () -> 2*X end ()) end). %% [2,4,6,8,10,12,14,16,18,20]
lib_misc:for(1, 10, fun (X) -> (fun () -> 2*X end)() end). %% [2,4,6,8,10,12,14,16,18,20]
lib_misc:for(1, 10, fun (X) -> fun () -> 2*X end() end). %% [2,4,6,8,10,12,14,16,18,20]
The problem is when I call
lists:nth(3, L)().
which gives the error * 1: syntax error before: '('. Why is this not giving 6? lists:nth() is a function which in this case returns another function. So what is causing this problem?
Wrapping the statement in parenthesis gives the expected result, but why so?
(lists:nth(3, L))(). %% 6
Similarly, assigning the return value to a variable and calling it works, but that's obvious.
-module(test).
-export([l/0, t/0]).
l() -> lib_misc:for(1, 10, fun (X) -> (fun () -> 2*X end) end).
%% t() -> lists:nth(3, l())(). %% test.erl:5: syntax error before: '('
t() -> lists:nth(3, l()). %% works.
If the problem is with statement expression thing, in this code fun (X) -> fun () -> 2*X end() end is the inner anonymous function a statement or an expression?
Thanks.
It's simply an effect of the precedence rules in the Erlang grammar. (And there are no statements in Erlang, only expressions.)
It is powerful technique using recursion because its strong describable feature. Tail recursion provides more powerful computation than normal recursion because it changes recursion into iteration. Continuation-Passing Style (CPS) can change lots of loop codes into tail recursion. Continuation Monad provides recursion syntax but in essence it is tail recursion, which is iteration. It is supposed to reasonable use Continuation Monad for 100000 factorial. Here is the code.
type ContinuationBuilder() =
member b.Bind(x, f) = fun k -> x (fun x -> f x k)
member b.Return x = fun k -> k x
member b.ReturnFrom x = x
(*
type ContinuationBuilder =
class
new : unit -> ContinuationBuilder
member Bind : x:(('d -> 'e) -> 'f) * f:('d -> 'g -> 'e) -> ('g -> 'f)
member Return : x:'b -> (('b -> 'c) -> 'c)
member ReturnFrom : x:'a -> 'a
end
*)
let cont = ContinuationBuilder()
//val cont : ContinuationBuilder
let fac n =
let rec loop n =
cont {
match n with
| n when n = 0I -> return 1I
| _ -> let! x = fun f -> f n
let! y = loop (n - 1I)
return x * y
}
loop n (fun x -> x)
let x2 = fac 100000I
There is wrong message: "Process is terminated due to StackOverflowException."
What is wrong with 100000 factorial using ContinuationMonad?
You need to compile the project in Release mode or check the "Generate tail calls" option in project properties (or use --tailcalls+ if you're running the compiler via command line).
By default, tail call optimization is not enabled in Debug mode. The reason is that, if tail-calls are enabled, you will not see as useful information about stack traces. So, disabling them by default gives you more pleasant debugging experience (even in Debug mode, the compiler optimizes tail-recursive functions that call themselves, which handles most situations).
You probably need to add this memeber to your monad builder:
member this.Delay(mk) = fun c -> mk () c
How can i return unit from an expression in f#? For example:
let readInt =
let str = Console.ReadLine()
let (succ, num) = Int32.TryParse(str)
match succ with
| true -> Some(num)
| _ -> None
match readInt with
| Some(v) -> Console.WriteLine(v)
| None -> ignore //i don't want to do anything,
// but i don't know how to ignore this brunch of the expression
The (only possible) unit value in F# is written as
()
So your code becomes
...
| None -> ()
Just write () as follows
match readInt with
| Some(v) -> Console.WriteLine(v)
| None -> ()
Keep in mind the unit value (), it is handy in many situations.
In this case, you could use iter function from Option module:
Option.iter Console.WriteLine readInt
It also highlights the fact that iter functions (e.g. those from Seq, List and Array module) will always give you the unit value ().
I'm stuck with a seemingly trivial problem: I'm unable to handle an exception in a function if it's written in a point-free manner.
Consider these two functions:
let divide1 x y =
try
x / y
with
| :? System.DivideByZeroException -> 42
let divide2 =
try
(/)
with
| :? System.DivideByZeroException -> fun _ _ -> 42
let x1 = divide1 5 0 // works fine
let x2 = divide2 5 0 // doesn't handle an exception
Although both functions are seemingly same, they have different types:
val divide1: int -> int -> int
val divide2: (int -> int -> int)
Obviously, divide2 does not even attempt to handle an exception. It simply returns an operator.
What can I do in order to make divide2 handle the exception in a proper manner (except specifically declaring its arguments)?
This is one of the reasons why I find the point-free style problematic. It makes it difficult to use standard language constructs like try .. with (or standard loops and other F# features) and you need to replace them with custom combinators. In this case, you could define combinator tryWith2 that wraps a two-argument function in an exception handler:
let tryWith2 f h a b =
try f a b // Call the function with two arguments
with e ->
// Try running the error handler with the exception
match h e with
| Some g -> g a b // Error handler provided another function
| _ -> reraise() // Error was not handled - reraise
Then you could write the function in a point-free style like this (the error handling is still not-point-free, but I do not want to make this too silly :-))
let divide2 =
tryWith2 (/) (function
| :? System.DivideByZeroException -> Some(fun _ _ -> 42)
| _ -> None)
let x1 = divide2 5 0 // returns 42
let x2 = divide2 5 1 // returns 5
Of course, the point free style is useful, even in F#. For example, when writing a DSL, it is a great way to compose declarative specification (because the primitives express something using higher-level of abstraction). Here, you need to express something that is quite close to normal F# code and, I believe, that is best expressed as normal F# code.
What you need to remember is that in divide2, you aren't returning the result of X divided by Y, you're returning a function that divides X by Y. The code for the let binding is being executed immediately because it isn't given function syntax. Let's look at both divide bindings with the longer function syntax:
let divide1 =
fun x ->
fun y ->
try
x / y
with
| :? System.DivideByZeroException -> 42
let divide2 =
try
fun x ->
fun y ->
x / y
with
| :? System.DivideByZeroException -> fun _ _ -> 42
When displayed this way, it should be clearer how the two definitions are different. The try block is in a completely different location, and executed at different points in time.
The only way to add logic such as exception handling to an existing function is to wrap it, either as you do in divide1, or with a higher order function as Tomas has shown.