I have the following code
let rec function1 element1 element2 = function
| [] -> []
| [a;b;c;d;e;f]::t -> if true then if true then [a]::(function1 element1 element2 t) else (function1 element1 element2 t)
| h :: t -> (function1 element1 element2 t);
,but it wont let me check if statement 1 and statement 2 is true
I keep getting
| [a;b;c;d;e;f]::t -> if true then if true then [a]::(function1 element1 element2 t) else (function1 element1 element2 t)
------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stdin(3,31): error FS0001: This expression was expected to have type
'a list
but here has type
unit
I tried many different things and it doesnt seem like i am trying something that shouldnt work. Help please
You statement is read as:
if true
then
if true
then something
else somethingElse
// missing else
If statement might omit else branch if type of overall expression should be unit. So when you omit else you can think of just adding else () by the compiler.
On the other hand you are defining that match statement should return a list.
As you have 2 if's but only 1 else branch, the compiler has inferred the return type to be unit as only 1 of the if expressions returns a non-unit.
You could fix this by either
1: remove the nesting - it's not necessary when you could && the conditions
2: add the extra else branch (which in you're case would return (function1 element1 element2 t))
Related
I have no idea what is the problem,
this is the code-
solve_bdd(BddTree, ListVars) ->
findRes(BddTree, maps:from_list(ListVars++[{one, 1}, {zero, 0}])).
findRes(BddTree, Map) when is_record(BddTree, node)-> Val = maps:get(getName(BddTree)), Name = getName(BddTree),
if Name=='one' or Name=='zero' -> maps:get(getName(BddTree));
(Val==1 or Val=='true') -> findRes(getRight(BddTree), Map);
(Val==0 or Val=='false') -> findRes(getLeft(BddTree), Map);
true -> error
end;
findRes(_, _) -> error.
And the shell errors-
exf.erl:183: syntax error before: '=='
exf.erl:180: function findRes/2 undefined
exf.erl:21: Warning: function getRight/1 is unused
exf.erl:22: Warning: function getLeft/1 is unused
error
When there is multiple conditions, You should group operands of or operator in parentheses:
1> false or false.
false
2> false == true or false == true.
* 1: syntax error before: '=='
2> (false == true) or (false == true).
false
Also maps:get/1 (function get in module maps which accepts 1 parameter) that you used:
maps:get( getName(BddTree) )
does not exists! But you can use maps:get/2 or maps:get/3.
Most of the time you can use case expression instead of if expression.
Also sometimes it's better to use orlese operator instead of or.
It's better to not handle anything! instead of handling both 0 and 1 and boolean types, you can use one of them and remove unnecessary checks.
By convention in Erlang it's better to write function and record names in Snake_case.
BTW, your findRes/2 function would be like:
%%% I don't know what work you expect from this function so if it's not working
%%% just like your own, try to fix it!
% findRes -> find_res
find_res(BddTree, Map) when is_record(BddTree, node) ->
% Sounds like BddTree is a record. If by `get_name/1` you just want to
% access one of it's elements, you can simply write BddTree#node.<ELEMENT_NAME>
% getName -> get_name
case get_name(BddTree) of
% you don't have to use ' character for atoms:
Name when Name == one orelse Name == zero ->
% I thinkd you've missed `Map`:
maps:get(get_name(BddTree), Map);
_ ->
% I do not use 0 and 1 and just use boolean type:
find_res(
% I thinkd you've missed `Map`:
case maps:get(get_name(BddTree), Map) of
Val when Val -> % when Val == true
% getRight -> get_right
get_right(BddTree);
_ -> % Assume false
get_left(BddTree)
end,
Map
)
end;
find_res(_, _) -> error.
And let's look at above code without comments:
find_res(BddTree, Map) when is_record(BddTree, node) ->
case get_name(BddTree) of
Name when Name == one orelse Name == zero ->
maps:get(get_name(BddTree), Map);
_ ->
find_res(
case maps:get(get_name(BddTree), Map) of
Val when Val -> % when Val == true
get_right(BddTree);
_ ->
get_left(BddTree)
end,
Map
)
end;
find_res(_, _) -> error.
I am trying figure out if a generic type wrapped in a rop result is a list or not. This is what I tried but I got errors.
let checkType (result : RopResult<'tSuccess, 'errors>) =
match result with
| Success (s, msg) ->
match s with
| :? [] -> // error here
Sample
let isList<'s> () = true
let processList (ls : 'domain list) = true
let processType (s : 'domain) = true
let checkType (result : RopResult<'tSuccess, 'errors>) =
match result with
| Success (s, msg) ->
match s with
| s when isList<s>() -> processList s
| _ -> processType s
| Failure (x) -> false
I'll first explain the technicalities of how to get your code to work, and then try to convince you (as the other folks on this thread) that it may not be the right way to approach your problem.
Firstly, your match statement has a syntax error. You would write the type test and the cast in one swoop as
match s with
| :? List<int> as theIntList -> ...do something with theIntList ...
When you add that to your code, the F# compiler will complain "The runtime coercion or type test ... involves an indeterminate type. ... Further type annotations are needed". Fix that by being more specific about what kind of result your checkType is processing: it is some System.Object instance and the message, so you'd write:
let checkType (result : Result<obj*string, 'errors>) =
match result with
| Success (s, msg) ->
match s with
| :? List<int> as theIntList -> ... do something
Note that you can't change that to a generic thing like List<_> - F# will do the type test and the cast in one go, and would not hence know what to cast to. If you try to, you will see warnings that your List<_> has been inferred to be List<obj>
Having said all that: Using obj is not the idiomatic way to go, as others have tried to point out already. The answers of #robkuz and #TheInnerLight contain all you need: A map function, functions that operate on individual result types, which then becomes nicely composable:
let map f x =
match x with
| Success (s, msg) -> Success (f s, msg)
| Failure f -> Failure f
// This will automatically be inferred to be of type Result<(int list * string), 'a>
let myFirstResult = Success ([1;2], "I've created an int list")
// This will automatically be inferred to be of type Result<(string list * string), 'a>
let mySecondResult = Success (["foo"; "bar"], "Here's a string list")
// Process functions for specific result types. No type tests needed!
let processIntList (l: int list) = Seq.sum l
let processStringList = String.concat "; "
// This will automatically be inferred to be of type Result<(int * string), 'a>
let mapFirst = myFirstResult |> map processIntList
// This will automatically be inferred to be of type Result<(string * string), 'a>
let mapSecond = mySecondResult |> map processStringList
I am not sure if I really understand your problem.
In general if you have some polymorphic type (like your RopResult) and you want to process the polymorphic part of it a good approach in F# would be
to disentagle your code into a wrapper code and a processor code where your processor code is delivered via a higher order function for the processing part.
Example:
type RopResult<'tSuccess, 'tError> =
| Success of 'tSuccess
| Error of 'tError
let checkType (process: 'tSuccess -> 'tResult) (result : RopResult<'tSuccess, 'tError>) =
match result with
| Success s -> process s |> Success
| Error e -> Error e
and
let processList (ls : 'domain list) = true
let processType (s : 'domain) = true
and then you
checkType processList aListWrappedInResult
checkType processType aTypeWrappedInResult
Assuming you wanted to determine whether a supplied value was of a generic list type, you could do this:
let isList value =
let valueType = value.GetType()
match valueType.IsGenericType with
|true -> valueType.GetGenericTypeDefinition() = typedefof<_ list>
|false -> false
Example usage:
isList [5];;
val it : bool = true
isList ["a", "b"];;
val it : bool = true
isList "a";;
val it : bool = false
When working with something like RopResult, or more formally, Either, it's helpful to define the map function. The map function takes a function 'a -> 'b and gives you a function which operates in some elevated domain, e.g. RopResult<'a,'c> -> RopResult<'b,'c>.
This is analogous to List.map : ('a ->'b) -> 'a List -> 'b List.
We define it like this:
let map f v =
match v with
|Success sv -> Success (f sv)
|Failure fv -> Failure (fv)
You can then use isList on RopResults by simply doing:
ropResult |> map isList
Others here are warning you in the comments that there may be potential issues surrounding how you actually process the results once you've determined whether the type is a list or not. Specifically, you will need to ensure that the return types of your processList and processType functions are the same (although I would recommend revisiting the naming of processType and call it processValue instead. Since you are not operating on the type, I think the name is confusing).
The following f# function works great if I pass references to objects, but will not accept structs, or primitives:
let TryGetFromSession (entryType:EntryType, key, [<Out>] outValue: 'T byref) =
match HttpContext.Current.Session.[entryType.ToString + key] with
| null -> outValue <- null; false
| result -> outValue <- result :?> 'T; true
If I try to call this from C# with:
bool result = false;
TryGetFromSession(TheOneCache.EntryType.SQL,key,out result)
I get The Type bool must be a reference type in order to use it as a parameter Is there a way to have the F# function handle both?
The problem is that the null value in outValue <- null restricts the type 'T to be a reference type. If it has null as a valid value, it cannot be a value type!
You can fix that by using Unchecked.defaultOf<'T> instead. This is the same as default(T) in C# and it returns either null (for reference types) or the empty/zero value for value types.
let TryGetFromSession (entryType:EntryType, key, [<Out>] outValue: 'T byref) =
match HttpContext.Current.Session.[entryType.ToString() + key] with
| null -> outValue <- Unchecked.defaultof<'T>; false
| result -> outValue <- result :?> 'T; true
I still think this is not "pretty"/idomatic F# code and would probably do some more seremonial with the following:
let myCast<'T> o =
match box o with
| :? 'T as r -> Some(r)
| _ -> None
let GetFromSession<'T> entryType key =
match HttpContext.Current.Session.[entryType.ToString + key] with
| null -> None
| r -> myCast<'T> r
This is also kind of "safer" and will (should?) not throw any exception, and it removes the null-stuff in F#. In C# it will return and work ok too, but None are returned as null, and if some result, well yeah it will be Some ;-)
Mind that the above code are not tested, not run in any setting or even compiled, so regard it as pseudo code. It might even have other issues...
Check also:
https://msdn.microsoft.com/en-us/library/dd233220.aspx
and
http://fsharpforfunandprofit.com/posts/match-expression/
On the last link especially: Matching on subtypes
On a side note, I do not like the missing checking of entire hierachy from HttpContext to Session are non-null, but that might just be me...
Update for some C# code using None/Some
var x = GetFromSession<MyTypeInSession>(entryType, key)?.Value??defaultValue;
There is absolutely no need for going full arabic, reading from right to left, and from down and up with a pyramidal scheme of ifs and buts and no candy or nuts, for null-checking et al ad nauseam.
And again code is to be regarded as pseudo code...
I have the following code
if somecondition then
myobj.Property1 = match myobj.Property1 with
| null -> SomePropertyType ()
| p -> p
What I am trying to do is to see if myobj.Property1 is null, if it is not then leave it alone otherwise create a new object of type SomePropertyType and assign it.
Problem is, I am getting a
This expression should have type 'unit', but has type 'bool'
And what should I do If I had to put multiple of those myobj.Property1 .... statements under that if ?
You are comparing two values (using =) so the return type will be bool, but if you have an if without else the compiler expect unit as return type.
I guess you intended to assign the value to the property, use <- instead:
if somecondition then
myobj.Property1 <- match myobj.Property1 with ...
Anyway if you want to check for null to assign a default value you don't need a match, an if then is enough:
if somecondition then
if (myobj.Property1 = null) then myobj.Property1 <- SomePropertyType ()
...
UPDATE
You can "merge" both if .. then to a single match:
match (somecondition, myobj.Property1) with
| true, null -> myobj.Property1 <- SomePropertyType ()
...
Working with Erlang's case, I'm facing a problem. The problem is the following:
other languages:
switch(A)
{
case "A" : case "B" :
//do something
break;
}
So, how to achieve the same thing using Erlang? Because sometimes it is very important to put conditions like these, to avoid overhead.
May be guards are what you want.
the_answer_is(N) when A == "A"; A == "B";
; - is OR
, - is AND
You can use case expressions in Erlang. The syntax is:
case Expression of
Pattern1 [when Guard1] -> Expr_seq1;
Pattern2 [when Guard2] -> Expr_seq2;
...
end
To quote Pragmatic Erlang:
case is evaluated as follows. First,
Expression is evaluated; assume this
evaluates to Value. Thereafter, Value
is matched in turn against Pattern1
(with the optional guard Guard1),
Pattern2, and so on, until a match is
found. As soon as a match is found,
then the corresponding expression
sequence is evaluated—the result of
evaluating the expression sequence is
the value of the case expression. If
none of the patterns match, then an
exception is raised.
An example:
filter(P, [H|T]) ->
case P(H) of
true -> [H|filter(P, T)];
false -> filter(P, T)
end;
filter(P, []) ->
[].
filter(P , L); returns a list of all those elements X in L for which P(X) is true. This can be written using pattern matching, but the case construct makes the code cleaner. Note that choosing between pattern matching and case expressions is a matter of taste, style and experience.
Not my favorite style, but you can do something like:
case A of
_ when A == "A";
A == "B" -> do_ab();
_ when A == "C";
_ when A == "D" -> do_cd();
_ -> do_default()
end.