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

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

Related

How can I improve my Haskell code and make it work?

In my code I call the validateFEN function with a FEN String. A Fen string looks like this for example:
",w84,w41,w56,w170,w56,w41,w84,/,,w24,w40,w17,w40,w48,,/,,,w16,w16,w16,,,/,,,,,,,,/,,,,,,,,/,,,,,,,,/,,,b1,b1,b1,,,/,,b3,b130,b17,b130,b129,,/,b69,b146,b131,b170,b131,b146,b69,"
The function should take the string and check if it's a FEN string.
How does it know if it's a FEN string? -> My string has 9 rows and 9 columns. I don't need to check if the pieces (example: w86) are at their right position.
validateFEN' b = help3 (filter (\x -> x == ',' || x == '/' ) b)
help3 b = (if help1 b == True then (if head (drop 8 b) == '/' then help3 (drop 9 b) else False) else False )
help1 b = help2 (take 8 b)
help2 b = foldr (+) 0 (map (\x -> if x == ',' then 1 else 0 )b) == 8
Why do I keep getting the error for a empty list?
Exception: Prelude.head: empty list
I understand that with my code there is no stop. The program doesn't know when the string is "correct".
Is there a shorter simpler way of doing this?
One way to reuse existing library functions to make this clearer would be to use stripPrefix.
help3 s = case stripPrefix ",,,,,,,,/" s of
Nothing -> False
Just s' -> help3 s'
Of course, you still need to handle the final case, where there is no terminating /. This can be done with a single extra clause:
help3 ",,,,,,,," = True
help3 s = {- ... -}
You might want to ponder whether validateFEN' should have a similar special case for the empty string.
BUT I would strongly suggest simply not implementing validateFEN' in the first place. My guess is that the plan is something like this:
Check if a string is valid FEN.
Process the string, assuming FEN-ness.
Instead, I recommend the following approach:
Parse the string into a native data structure that represents the information available in a FEN string.
Process the native structure.
Step 1, if written with standard parsing solutions, will "accidentally" validate the string -- i.e. running your parser will return something like Either Error FEN, which you can pattern match on to either discover that the string is invalid or that it is valid and has been turned into a more idiomatic representation.

badarg to '++'operator - How to come around?

** Reason for termination =
** {badarg,[{erlang,'++',[<<>>,"</after></set></query></iq>"]},
{geoloc,get_nearby,1},
And the method was:
get_nearby({_Pid, DynVars})->
%Last = ts_dynvars:lookup(last, DynVars),
Last = lists:keysearch(last,1,DynVars),
{ok, Rad} = ts_dynvars:lookup(rad,DynVars),
{ok, Lat} = ts_dynvars:lookup(lat,DynVars),
{ok, Lon} = ts_dynvars:lookup(lon,DynVars),
if is_tuple(Last) ->
{value,{Key,After}} = Last,
if length(After) == 0 ->
After2 = "0";
true ->
After2 = After
end,
"<iq id=\"" ++ common:get_random_string(5,"abcdefghijklmnopqrstuvwxyz0123456789-+=") ++ "\" xmlns=\"http://xmpp.xgate.com.hk/plugins\" to=\"xmpp.xgate.hk.com\" type=\"get\"><query xmlns=\"jabber:iq:geoloc\"><geoloc><lat>" ++ Lat ++ "</lat><lon>" ++ Lon ++ "</lon><radius>" ++ Rad ++ "</radius></geoloc><set xmlns=\"http://jabber.org/protocol/rsm\"><max>" ++ integer_to_list(ran_max()) ++ "</max><after>" ++ After2 ++ "</after></set></query></iq>";
true -> % Last is boolean, namely the 'false' atom
ts_dynvars:set([rad, lat, lon], [Rad, Lat, Lon], DynVars),
"<iq id=\"" ++ common:get_random_string(5,"abcdefghijklmnopqrstuvwxyz0123456789-+=") ++ "\" xmlns=\"http://xmpp.xgate.com.hk/plugins\" to=\"xmpp.xgate.hk.com\" type=\"get\"><query xmlns=\"jabber:iq:geoloc\"><geoloc><lat>" ++ Lat ++ "</lat><lon>" ++ Lon ++ "</lon><radius>" ++ Rad ++ "</radius></geoloc><set xmlns=\"http://jabber.org/protocol/rsm\"><max>" ++ integer_to_list(ran_max()) ++ "</max></set></query></iq>"
end.
You are trying to concatenate a binary (<<>>) and a string, but ++ can only concatenate two strings (or lists - Erlang strings are actually lists).
That means that After2 is a binary, and consequently it received this value in the second clause of the if expression. Normally calling length(After) when After is not a list would cause a badarg exception, but as it appears in an if test it is treated as a guard test and exceptions are ignored, and therefore length(After) == 0 is treated as false. So the corresponding value was a binary already when you got it in DynVars.
A few suggestions:
To check whether a list is empty, it is somewhat wasteful to call length on it, as length needs to go through the entire list. Instead, write something like:
case After of
"" ->
After2 = "0";
[_|_] ->
After2 = After
end
[_|_] is a pattern that matches non-empty lists. In your case, the value of After would not match any of the clauses, and you'd have a case_clause error that tells you what value you actually got.
Of course, if you actually expect a binary here, check for <<>> and <<_/binary>> instead.
You're doing quite a few concatenations (++) there. In the expression A ++ B, the ++ operator needs to walk along the entire list in A, and thus the run time is proportional to the length of A.
There are two common alternatives to concatenation. First, often the function that will consume the result doesn't actually need a flat list, but would be equally happy with a "deep list" or "iolist" - instead of "foo" ++ "bar", write ["foo", "bar"]. Notably, if you're going to write the result to a file or send it to a socket, both file:write and gen_tcp:send accept both variants.
Second, you could use binaries instead of strings. Binaries are different from strings in many interesting ways (not the least how they behave with respect to garbage collection), but they do have the nice property that they can be concatenated efficiently. If A and B are binaries, and you write C = <<A/binary, B/binary>>, and the compiler can see that you only use C but not A after that, B will simply be concatenated to the memory area that held A. See the chapter on binary handling in the Efficiency Guide for more details.
The two lines starting with "<iq id=\"" are nearly identical, except that the first one inserts "<after>" ++ After2 ++ "</after>" in the middle. You could have the first case clause set MaybeAfter = "<after>" ++ After2 ++ "</after>" and the second case clause set MaybeAfter = "", and then have one single line that inserts the value of MaybeAfter in the right place. That would help making the code more readable.

Haskell exceptions and unit testing

Based on SO question 13350164 How do I test for an error in Haskell?, I'm trying to write a unit test which asserts that given invalid input, a recursive function raises an exception. The approach I adopted works well for non-recursive functions (or when the first call raises the exception), but as soon as the exception occurs deeper in the call chain, the assertion fails.
I've read the excellent answers to question 6537766 Haskell approaches to error handling but unfortunately the advice is a bit too generic for this point of my learning curve. My guess is that the problem here is connected to lazy evaluation and non-pure testing code, but I'd appreciate an expert explanation.
Should I take a different approach to error handling in situations like this (e.g. Maybe or Either), or is there a reasonable fix for making the test case work correctly while using this style?
Here's the code I've come up with. The first two test cases succeed, but the third one fails with "Received no exception, but was expecting exception: Negative item".
import Control.Exception (ErrorCall(ErrorCall), evaluate)
import Test.HUnit.Base ((~?=), Test(TestCase, TestList))
import Test.HUnit.Text (runTestTT)
import Test.HUnit.Tools (assertRaises)
sumPositiveInts :: [Int] -> Int
sumPositiveInts [] = error "Empty list"
sumPositiveInts (x:[]) = x
sumPositiveInts (x:xs) | x >= 0 = x + sumPositiveInts xs
| otherwise = error "Negative item"
instance Eq ErrorCall where
x == y = (show x) == (show y)
assertError msg ex f =
TestCase $ assertRaises msg (ErrorCall ex) $ evaluate f
tests = TestList [
assertError "Empty" "Empty list" (sumPositiveInts ([]))
, assertError "Negative head" "Negative item" (sumPositiveInts ([-1, -1]))
, assertError "Negative second item" "Negative item" (sumPositiveInts ([1, -1]))
]
main = runTestTT tests
It's actually just an error in sumPositiveInts. Your code does not do negativity checking when the only negative number is the last one in the list—the second branch doesn't include the check.
It's worth noting that the canonical way of writing recursion like yours would break the "emptiness" test out in order to avoid this bug. Generally, decomposing your solution into "sum" plus two guards will help to avoid errors.
I second the suggestion from Haskell approaches to error handling by the way. Control.Exception is much more difficult to reason about and learn and error should only be used to mark code branches which are impossible to achieve—I rather like some suggestions that it ought to have been called impossible.
To make the suggestion tangible, we can rebuild this example using Maybe. First, the unguarded function is built in:
sum :: Num a => [a] -> a
then we need to build the two guards (1) empty lists give Nothing and (2) lists containing negative numbers give Nothing.
emptyIsNothing :: [a] -> Maybe [a]
emptyIsNothing [] = Nothing
emptyIsNothing as = Just as
negativeGivesNothing :: [a] -> Maybe [a]
negativeGivesNothing xs | all (>= 0) xs = Just xs
| otherwise = Nothing
and we can combine them as a monad
sumPositiveInts :: [a] -> Maybe a
sumPositiveInts xs = do xs1 <- emptyIsNothing xs
xs2 <- negativeGivesNothing xs1
return (sum xs2)
And then there are lots of idioms and reductions we can employ to make this code much easier to read and write (once you know the conventions!). Let me stress that nothing after this point is necessary nor terribly easy to understand. Learning it improves your ability to decompose functions and fluently think about FP, but I'm just jumping to the advanced stuff.
For instance, we can use "Monadic (.)" (which is also called Kleisli arrow composition) to write sumPositiveInts
sumPositiveInts :: [a] -> Maybe a
sumPositiveInts = emptyIsNothing >=> negativeGivesNothing >=> (return . sum)
and we can simplify both emptyIsNothing and negativeGivesNothing using a combinator
elseNothing :: (a -> Bool) -> a -> Just a
pred `elseNothing` x | pred x = Just x
| otherwise = Nothing
emptyIsNothing = elseNothing null
negativeGivesNothing = sequence . map (elseNothing (>= 0))
where sequence :: [Maybe a] -> Maybe [a] fails an entire list if any of the contained values are Nothing. We can actually go one step further since sequence . map f is a common idiom
negativeGivesNothing = mapM (elseNothing (>= 0))
So, in the end
sumPositives :: [a] -> Maybe a
sumPositives = elseNothing null
>=> mapM (elseNothing (>= 0))
>=> return . sum

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.

What to use instead of a list comprehension

I'm just getting started with Haskell and finished a nice exercise to make a Caesar cipher.
One of the first steps was to make a function that will take a letter and turn it into a number. I know that chr and ord can do this already but part of the exercise was to write your own.
let2num c = head [ b | (a,b) <- zip ['a'..'z'] [0..25], a==c]
I'm new to the Haskell syntax and one of the first things I learned was list comprehensions, so that has become my hammer. I'm very curious though, what is another (likely better) way to write this function?
If you're curious the rest of the cipher is in a gist.
EDIT
I'm also interested in other ways to translate back from numbers to letters.
num2let d = head [ a | (a,b) <- zip ['a'..'z'] [0..25], b==(d `mod` 26)]
My solution:
import Data.List
let2num c = let (Just n) = elemIndex c ['a'..'z'] in n
Or:
import Data.List
import Data.Maybe
let2num c = fromJust $ elemIndex c ['a'..'z']
Or in pointless style:
import Data.List
import Data.Maybe
let2num = fromJust . (flip elemIndex) ['a'..'z']
The function elemIndex returns the index of the first element in the given list which is equal (by ==) to the query element, or Nothing if there is no such element.
The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.
The function fromJust extracts the element out of a Just.
The reverse process:
num2let = (!!) ['a'..'z']
!! is a List index (subscript) operator, starting from 0. It is an instance of the more general Data.List.genericIndex, which takes an index of any integral type.
(!!) is partially applied here, which means it still needs one argument of type Int to yield the result (a value from the list whose index equals to Int value you pass to num2let).
“Caesar simply replaced each letter in the message by the letter three places further down the alphabet, wrapping around at the end of the alphabet.” We can simply write it in Haskell. In fact we can avoid let2num and num2let altogether.
So let's start with defining a table to map plain text alphabet to the cipher text alphabet:
cipher = let abc = ['a'..'z']
code = drop 3 abc ++ take 3 abc
in zip abc code
It will look like
[('a','d'),('b','e'),('c','f'),('d','g'), ... ]
Now we can encrypt a symbol, if we simply lookup the letter in this dictionary:
ghci> lookup 'a' cipher
Just 'd'
lookup returns a Maybe Char value, we need to convert it to simply a Char, and for this I use maybe function, using '?' for symbols which were not found in the cipher, and id (identity function = no changes) to found symbols:
ghci> maybe '?' id (lookup 'a' cipher)
'd'
Now we can write an encrypt function to encode just one symbol, it will leave missing characters, like a space, unencrypted:
encrypt c = maybe c id (lookup c cipher)
To encrypt an entire string:
ghci> map encrypt "haskell is fun"
"kdvnhoo lv ixq"
So we can put it all together:
encrypt c = maybe c id (lookup c cipher)
where
cipher = let abc = ['a'..'z']
code = drop 3 abc ++ take 3 abc
in zip abc code
For completeness, I think somebody should mention that list comprehensions are just a shortcut for writing stuff in the list monad. Your code transcribed is, roughly, this:
let2num c = head $ do (a,b) <- zip ['a'..'z'] [0..25]
if a == c then [b] else []
Not a very interesting example, but there you go.
Also, de-sugaring the do syntax, this is the same:
let2num c = head $ zip ['a'..'z'] [0..25] >>= \(a,b) -> if a == c then [b] else []
I'm not sure why you are opposed to the ord solution. List-based solutions perform unnecessary work (traversing a list). And they still are desugared into invocation of the enumFromTo, a method of the Enum class which allows to convert between Ints and Chars in the same way as ord/chr do. This is the lowest-level interface provided for Char type, so you hardly can "write your own" here (apart from doing boxing/unboxing yourself, but this is not a big joy).
I would go with the following:
import Data.Char
caesar :: Int -> Char -> Char
caesar n c = if isAlpha c
then chr (ord 'a' + (ord c - ord 'a' + n) `mod` 26)
else c
and map (caesar n) over the string with n the desired offset.