Erlang: How to "Do Nothing" in true branch of if statement - if-statement

I have this if statement:
if
A /= B -> ok;
true ->
end.
I want it to do nothing when A == B.

Erlang does not have the notion of nothing like void or unit. I would suggest returning another atom like not_ok (or even void or unit.)

The best answer is don't use if, just use case.
case A of
B -> ok;
C -> throw({error,a_doesnt_equal_b_or_whatever_you_want_to_do_now})
end
typically ok or undefined or noop are returned as atoms which mean essentially, nothing.

As said, any code will return something.
If you want to do something only in one case, then you can write this:
ok =if
A /= B -> do_something(A,B); % note that in this case do_something must return ok
true -> ok
end.
if you want to get new values for A, B you can write this
{NewA,NewB} = if
A /= B -> modify(A,B); % in this case modify returns a tuple of the form {NewA,NewB}
true -> {A,B} % keep A and B unchanged
end.
% in the following code use only {NewA,NewB}
or in a more "erlang way"
%in your code
...
ok = do_something_if_different(A,B),
{NewA,NewB} = modify_if_different(A,B),
...
% and the definition of functions
do_something_if_different(_A,_A) -> ok;
do_something_if_different(A,B) ->
% your action
ok.
modify_if_different(A,A) -> {A,A};
modify_if_different(A,B) ->
% insert some code
{NewA,NewB}.
last if you expect that it crashes if A == B
%in your code
...
ok = do_something_if_different_else_crash(A,B),
...
% and the definition of functions
do_something_if_different_else_crash(A,B) when A =/= B ->
% your action
ok.

Related

Error SML: unbound variable or constructor

I am new to SML. I tried to create and test the following function below, but I received an error. I do not know what is the problem.
fun isOld(pFirstTuple: int*int*int, pSecondTuple: int*int*int) =
if (#1 pFirstTuple) < (#1 pSecondTuple)
then
true
if (#1 pFirstTuple) = (#1 pSecondTuple)
then
if (#2 pFirstTuple) < (#2 pSecondTuple)
then
true
else
false
I have tried this command "val p = isOld((8,9,10),(10,11,12))", but it showed me the following error Unbound variable or constructor. How do I fix this?
Here's what your code looks like, stripped down by ignoring various subexpressions (replacing them with A, B, and C)
if A
then true
if B
then if C
then true
else false
You're making extensive use of if/then/else, but the syntax is not quite correct. In SML, every if must have both a then and else clause associated with it. Here's my guess at what you actually meant:
if A
then true
else if B
then if C
then true
else false
else false
This is starting to get quite messy---but you can clean it up with boolean logic. Notice, for example, that if X then true else false means exactly the same thing as simply writing X, because both expressions are type bool and will always evaluate to the same boolean, regardless of what X is. You can extend this reasoning to see that
if X then true else Y is equivalent to X orelse Y.
if X then Y else false is equivalent to X andalso Y.
With these ideas, we can clean up your code considerably:
A orelse (B andalso C)

How do I validate arguments to a Haskell "public safe" constructor?

In my Python package I have a function I use to create validated instances of my class, with something like
#staticmethod
def config_enigma(rotor_names, window_letters, plugs, rings):
comps = (rotor_names + '-' + plugs).split('-')[::-1]
winds = [num_A0(c) for c in 'A' + window_letters + 'A'][::-1]
rngs = [int(x) for x in ('01.' + rings + '.01').split('.')][::-1]
assert all(name in rotors for name in comps[1:-1])
assert comps[-1] in reflectors
assert len(rngs) == len(winds) == len(comps)
assert all(1 <= rng <= 26 for rng in rngs)
assert all(chr_A0(wind) in LETTERS for wind in winds)
#...
and I would like to enforce the same behavior in Haskell. But doing so in the same way — with assertions — does not work, because Haskell assertions are disabled in general (unless certain compiler flags are set). For example, in something like
configEnigma rots winds plug rngs =
assert ((and $ (==(length components')) <$> [length winds', length rngs']) &&
(and $ [(>=1),(<=26)] <*> rngs') &&
(and $ (`elem` letters) <$> winds') &&
(and $ (`M.member` comps) <$> tail components'))
-- ...
where
rngs' = reverse $ (read <$> (splitOn "." $ "01." ++ rngs ++ ".01") :: [Int])
winds' = "A" ++ reverse winds ++ "A"
components' = reverse $ splitOn "-" $ rots ++ "-" ++ plug
can't be relied on to work because the assertions will be removed in most contexts.
What is an idiomatic and reliable way to force all my instances to be validated in Haskell (using a "public safe" constructor)?
The normal thing is to express failure explicitly. For example, one might write
configEnigma :: ... -> Maybe ...
configEnigma ... = do
guard (all (((==) `on` length) components') [winds', rngs'])
guard (all (inRange (1,26)) rngs')
guard (all (`elem` letters) winds')
guard (all (`M.member` comps) (tail components'))
return ...
where
...
You might even consider upgrading from Maybe to Except Error for some custom-defined type Error, to communicate to the caller what it was that went wrong during construction. Then instead of guard, you could use a construction like:
unless (all (inRange (1,26)) rngs') (throwError OutOfRange)
The caller to configEnigma will have to express how to handle failures. For Maybe, this looks like
case configEnigma ... of
Just v -> -- use the configured enigma machine v
Nothing -> -- failure case; perhaps print a message to the user and quit
while with Except you get information about what went wrong:
case runExcept (configEnigma ...) of
Right v -> -- use the configured enigma machine v
Left err -> -- failure case; tell the user exactly what went wrong based on err and then quit

Haskell append to a list conditionally

I have 2 lists which I am trying to fill will items. While reading from stdin, depending on the value of one of the things read, I want to append to a different list. Example,
import Control.Monad(replicateM)
main = do
n <- getLine
let l1 = [], l2 = []
in replicateM (read n) (getLine >>= (\line ->
case line of "Yes" ->
-- do something with line
-- and append value of that thing to l1
"No" ->
-- do something else
-- append this value to l2
putStrLn line))
I realise the above code has syntax errors and such, but hopefully you can see what I am trying to and suggest something.
This is the answer I came up with
While we are at it, can someone explain why this gives me an infinite list:
let g = []
let g = 1:g
-- g now contains an infinite list of 1's
This is what I finally came up with:
import Control.Monad(replicateM)
import Data.Either
getEither::[String] -> [Either Double Double]
getEither [] = []
getEither (line:rest) = let [n, h] = words line
fn = read f :: Double
e = case heist of "Yes" -> Left fn
"No" -> Right fn
in e : getEither rest
main = do
n <- getLine
lines <- replicateM (read n) getLine
let tup = partitionEithers $ getEither lines :: ([Double], [Double])
print tup
Not sure how fmap could have been used in this instance
Here is a short ghci session that may give you some ideas:
> :m + Control.Monad Data.Either
> partitionEithers <$> replicateM 3 readLn :: IO ([Int], [Bool])
Left 5
Right True
Left 7
([5,7],[True])
The answer to your second question is that let is recursive; so the two gs in let g = 1:g are referring to the same in-memory object.
You are thinking in term of mutable variables: you are "initializing" l1,l2 to the empty list and then reasoning about updating them with longer lists. This design works fine in imperative programming, but not so simply in pure functional programming since it involves mutation.
Now, even in pure functional programming we have ways to simulate mutation, through monads. For instance, once can achieve mutation here through IORefs or StateT IO. In this case, though, is would be an unnecessarily complex way to solve the task.
You want to append data to form two lists. You want to use replicateM, which is fine. The point is that replicateM will build just one list, instead of two. The question now is: how can we create a list which is easily split into two?
A first ugly attempt is to generate a list of tagged values, i.e. a list of pairs:
case line of
"Yes" -> let value = ... in
return ("for l1", value)
"No" -> let value = ... in
return ("for l2", value)
Doing this would make replicateM produce a list such as
[("for l1", value1), ("for l1", value2), ("for l2", value3), ...]
which we can then split into two lists.
The use of strings for tags looks however a bit unelegant, since a boolean would suffice:
case line of
"Yes" -> let value = ... in
return (True, value)
"No" -> let value = ... in
return (False, value)
An even better approach would be to use the Either a b type:
case line of
"Yes" -> let value1 = ... in
return (Left value1)
"No" -> let value2 = ... in
return (Right value2)
The nice consequence of the above is that value1 and value2 can even be of different types. The previous snippets forced them to share their type: since we build a list of pairs each pair must have the same type. The new list is now instead of type [Either a b] where a is the type of values to be put in l1, and b that for l2.
Once you get a [Either a b] you want to split it in [a] and [b]. As #DanielWagner suggests in his answer, you can exploit partitionEithers for this.

How to use closures in Erlang?

I have two lists: L and E. I try to write a function, which returns another list with number of occurences from L for elements in E.
-module(mymodule).
-export([count/2]).
-export([numberOfOccurences/2]).
count([Head|Tail], Counter) ->
fun(Element) -> if
[Head|Tail] == [] -> Counter;
Element == Head -> count(Tail, Counter + 1);
Element /= Head -> count(Tail, Counter)
end
end.
numberOfOccurences(L, E) ->
lists:map(count(L, 0), E).
mymodule:numberOfOccurences[1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]) should returns [4,2,0,2]. But it returns a list with 4 functions. What am I doing wrong?
What's happening here, is, if we unroll this map, count(L, 0) is being called first, then that resultant fun is being passed to lists:map. When that resultant fun is being mapped with each member of E, and being passed to the anonymous function, the return value for most of the elements is the result of calling count(Tail,Counter), which returns a function.
Here's a rewritten version of your functions that works. The big thing is
I fixed the base case, otherwise, you'll likely run into a match error when the empty-set is passed to count(), and more importantly,
In your closure, in order to ensure the proper recursion, you need to call the return value of count(), so I'm storing the result of count() calls into F, then calling that function with the passed element.
So here is the updated module:
-module(mymodule).
-export([count/2]).
-export([numberOfOccurences/2]).
count([],Counter) ->
fun(_) -> Counter end;
count([Head|Tail], Counter) ->
fun(Element) ->
if
Element == Head ->
F = count(Tail, Counter + 1),
F(Element);
Element /= Head ->
F = count(Tail, Counter),
F(Element)
end
end.
numberOfOccurences(L, E) ->
lists:map(count(L, 0), E).
Results:
> mymodule:numberOfOccurences([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
[4,2,0,2]
Let us look at your function count/2.
count([Head|Tail], Counter) ->
fun(Element) -> if
[Head|Tail] == [] -> Counter;
Element == Head -> count(Tail, Counter + 1);
Element /= Head -> count(Tail, Counter)
end
end.
This function contains statement that is the definition of a function. This being the last statement it becomes the return value. So the call:
lists:map(count(L, 0), E).
indeed returns a list of functions.
Looking at the definition of the count function, it indeed makes recursive calls to count and might actually work if it was ever called, which it isn't.
We could add one statement to the end of your program to call all the elements of the by changing the call in this way:
numberOfOccurences(L, E) ->
[F(E) || F <- lists:map(count(L, 0), E)].
Or alternatively, if you have a preference for the map function:
numberOfOccurences(L, E) ->
lists:map(fun(F) -> F(E) end, lists:map(count(L, 0), E)).
However these do not run.
mymodule:numberOfOccurences([1,2,"abc",2,1,"abc",4,1,1],
[1,2,3,"abc"]).
** exception error: bad function 4
in function mymodule:'-numberOfOccurences/2-lc$^0/1-0-'/2 (/home/tony/Projects/temp/src/mymodule.erl, line 20)
3>
As a matter of style the code would be easier to reason about if count parameters were passed rather than using closures in this way. Sometimes closures are essential such as when using spawn/1, but this is not one of those cases.
Analysing the problem I agree the first stage is a map, however I suggest counting matching elements is best achieved with a fold. However I will generally substitute a list comprehension for a map call. I just think it looks tidier.
So here is my solution:
-module occurances.
-export [count/2].
count(Data,KeyList) ->
[ lists:foldl(
fun(X,Count) when X =:= Key -> Count+1;
(_,Count) -> Count
end,
0,Data)
|| Key <- KeyList].
Note pattern matching with the value Key inside the foldl function will result in a shadow variable warning. X =:= Key is used instead.
occurances:count([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
[4,2,0,2]
So having made the code actually work how about putting into a closure so that spawn/1 could be called for example. Let us edit our working code module to make such a closure, and let the closure write the result to standard io so we can see the result.
make_closure(Data,KeyList) ->
fun() ->
io:format("~p~n",[count(Data,KeyList)])
end.
8> F=occurances:make_closure([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
F=occurances:make_closure([1,2,"abc",2,1,"abc",4,1,1], [1,2,3,"abc"]).
#Fun<occurances.0.132489632>
9> spawn(F).
spawn(F).
[4,2,0,2]
<0.107.0>
10>
For the record, you don't need a closure to define count.
In my book, it's much clearer to have an explicit count function, and plug it appropriately.
Edit: I've put list parameter second, to match lists module API.
count(X, [], Acc) -> Acc;
count(X, [X|T], Acc) -> count(T, X, Acc+1);
count(X, [_|T], Acc) -> count(T, X, Acc).
numberOfOccurences(L, E) ->
[count(X, L, 0) || X <- E].

Error: Instance : Num (a -> b) when I try to get the sign of the elements of a list

This is what I want to do:
INPUT: [1,2,3,-1,-2,-3]
OUTPUT:[1,1,1,-1,-1,-1]
I tried this:
signNum (x:n) = map(if x>0
then 1
else -1)n
Can anyone tell me where I've made a mistake in the logic?
The first problem is that map expects a function. So you have to wrap your if statement in a lambda. However, this will still not do exactly what you want. Instead of breaking the list into its head and tail, your really want to map your function over the whole list.
Remember that map just takes a function and applies it to each element. Since you want to turn each element into either 1 or -1, you just need to map the appropriate function over your list.
So in the end, you get:
sigNum ls = map (\ x -> if x > 0 then 1 else - 1) ls
In this case, it is probably easier to break the function down into smaller parts.
At the very lowest level, one can compute the signum of a single number, i.e.:
signum :: (Num a, Ord a) => a -> a
signum x = if x > 0 then 1 else -1
Once you have this, you can then use it on a list of numbers, like you would for any function:
signNum ls = map signum ls
(p.s. what is signum 0 meant to be? Your current definition has signum 0 = -1.
If you need to expand the function to include this case, it might be better to use guards:
signum x | x < 0 = -1
| x == 0 = 0
| otherwise = 1
or a case statement:
signum x = case compare x 0 of
LT -> -1
EQ -> 0
GT -> 1
)
Your comments suggest you'd like to be able to do this with a comprehension.
How to use a comprehension
If you do want to do this with a comprehension, you can do
signNum ls = [ if x>0 then 1 else -1| x <- ls ]
How not to use a comprehension
...but you can't put the condition on the right hand side
brokenSignNum ls = [ 1| x <- ls, x > 0 ]
Because putting a condition on the right hand side removes anything that
doesn't satisfy the condition - all your negatives get ignored! This would
shorten your list rather than replace the elements. Let's try
brokenSignNum2 ls = [ 1| x <- ls, x > 0 ] ++ [ -1| x <- ls, x <= 0 ]
This has the same length as your original list but all the positives are at the front.
Summary: you have to put this conditional expression on the left hand side
becuase that's the only place substitution can happen - on the right hand side it does deletion.
Is zero negative?
Note that your if statement counts 0 as negative. Are you sure you want that? Perhaps you'd be better with defining the sign of a number seperately:
sign x | x == 0 = 0 -- if x is zero, use zero
| x > 0 = 1 -- use 1 for positives
| x < 0 = -1 -- use -1 for negatives
workingSignNum1 ls = [sign x | x <- ls]
But sign is (almost) the same as the function signum, so we may as well use that
workingSignNum2 ls = [signum x | x <- ls]
Making it tidier
Now that's a lot of syntax for what basically means "replace x with sign x all along the list ls". We do that kind of thing a lot, so we could write a function to do it:
replaceUsing :: (a -> b) -> [a] -> [b]
replaceUsing f xs = [f x | x <- xs]
but there's already a function that does that! It's called map. So we can use map on our list:
quiteSlickSignNum :: Num a => [a] -> [a]
quiteSlickSignNum ls = map signum ls
or even slicker:
slickSignNum :: Num a => [a] -> [a]
slickSignNum = map signum
which is how I would have defined it.
Why did you say sign was almost the same as signum?
sign takes a number and returns a number, 1, 0, or -1, but what's the type of 1?
Well, 1 has the type Num a => a so you can use it with any numeric type. This means
sign takes any type of number and returns any type of number, so its type is
sign :: (Num a,Num b) => a -> b
so my version of sign can give you a different type. If you try it out, you'll find that 3 * sign 4.5 gives you 3, not 3.0, so you can get an Integer out of it, but also if you do 3.14 * sign 7.4, you get 3.14, so you can get a decimal type too. By contrast,
signum :: Num a => a -> a
so it can only give you back the type you gave it - 3 * signum 4.5 gives you 3.0.
The error message "no instance for Num" is one of the trickiest for new Haskellers to decipher. First, here's the fully polymorphic type signature for the function you are trying to write (I added this to the source file in order to get the same error as you):
signNum :: (Ord a, Num a) => [a] -> [a]
Finding the error
Now, the compile error message says:
Could not deduce (Num (a -> a)) from the context (Ord a, Num a)
arising from the literal `1' at prog.hs:3:17
Notice that the error message gives us the location of the problem. It says that "the literal 1" at file_name.hs:line_number:column_number is the problem.
signNum (x:n) = map(if x>0
then 1 -- <-- here's the problem! (according to that message)
else -1)n
Understanding the error
Now, the error message also suggests some possible fixes, but whenever you run into "no instance for Num", the suggested "possible fixes" are almost always wrong, so ignore them. (I wish GHC would provide better error messages for Num-related stuff like this).
Recall what the error message said:
Could not deduce (Num (a -> a)) ... arising from the literal `1' ...
What this means is that you put a literal 1 somewhere where the context expected something of type
a -> a. 1 is obviously not a function, so either the context is wrong, or the number 1 is wrong.
So what is the context of the literal 1?
Finding the error (precisely)
(if x > 0
then <<hole>>
else -1)
If statements in Haskell produce a value. The branches of an if statement must have the same type, and the type of the if statement is determined by the type of the branches.
Here, the other branch has the value -1, which is a number. So we therefore expect the <<hole>> to have the same type: a number. Well, this obviously isn't the problem (since 1 is a number), so let's look at the context of that expression.
map <<hole>> n
The map function expects a function as its first argument. However, we know the <<hole>> will produce a number. Eureka! Here's the discrepancy: we're giving map a number where it expects a function.
Correcting the error
The obvious solution -- now that we know precisely what and where the problem is -- is to give map a function, rather than a number. See the various other answers for details.