New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dibs: I will implement exercise atbash-cipher #72
Conversation
@stevejb71 I would love you feedback on this. I might have gone overboard and missing some Core library functions for this exercises. Besides that, two test cases fail, and I can't figure out why? Would appreciate any pointers you might have. |
Happy to give feedback. I'll take a look later today (Hong Kong time). |
| (_, []) -> [] | ||
| (_, _::xs) -> drop (n-1) xs | ||
|
||
let rec group n l = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has a bug: if the length of the list is 0 then it returns [[]]
, it should return []
. That should fix the broken tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch! Will definitely look into that.
I should have tested these methods as well, but I didn't want to enforce an implementation direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You were right not to publish tests for these internal function as they are implementation details. I just run adhoc tests in utop in this case.
| 'a' .. 'z' | '0' .. '9' -> true | ||
| _ -> false | ||
|
||
let explode s = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature of this function is not immediately obvious (at least to me!). A Haskell convention is to provide type signatures on top level functions in a module - that gives useful, and compiler checked, documentation. I'd favour the same in Ocaml code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was not sure what the OCaml convention is. I myself would rather provide type signatures for everything, although this takes away the benefit of type inference.
I will provide the type signatures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There a good summary of the benefits of type signatures on stackoverflow
http://stackoverflow.com/questions/23401698/what-is-a-good-reason-to-use-a-type-signature-for-functions-when-the-compiler-ca
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have troubles providing an inline signature because of the use of function
. Because it is an implementation detail, I can't provide the signature in the mli
-file.
Do you have a tip?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know of a way of providing a signature in this case. Either rewrite if you think adding a signature is worth it, or leave as is.
else | ||
(take n l) :: (group n (drop n l)) | ||
|
||
let encode ?block_size:(block_size = 5) word = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps text
is better than word
- the input can be more than 1 word.
Also, the optional parameter can be provided more simply:
?(block_size = 5)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, text
is a better name.
I will adopt your improvement for the optional parameter
let filtered_characters = List.filter is_encodable characters in | ||
let groups = group block_size filtered_characters in | ||
let preprocessed_words = List.map implode groups in | ||
let words = List.map (fun (word) -> (String.map substitute word)) preprocessed_words in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might as well take advantage of currying here:
let words = List.map (String.map substitute) preprocessed_words in
In any event, you don't need the brackets around the word
parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! That is a very good suggestion
@@ -0,0 +1,5 @@ | |||
(* Encoding from English to atbash cipher *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default value block_size is 5 according to the README. You might want to specify that in the comment. (I don't think there is anyway to specify a default value for a parameter in the .mli code.)
|
||
let ae exp got _test_ctxt = assert_equal ~printer:String.to_string exp got | ||
|
||
let tests = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should add a couple of tests with a different block size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly!
@@ -0,0 +1,57 @@ | |||
let substitute = function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are not using Core here. That would make implementation a touch easier (no need to rewrite drop and take).
Do you prefer not to use it, or was it an oversight?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was an oversight. Implementing take and drop distracts from the actual exercise.
Besides that, seeing that I made an incorrect implementation, I am in favour of _drop_ping (pun intended) the custom implementation for the ones in Core
@dvberkel - I added a few comments - one of them includes how to fix the tests. Let me know when you are done making the changes you accept, and I can re-review. |
@stevejb71 thanks for your review. They are very worthwhile. I will improve the code with your suggestions later today. I will drop you a line when I am finished |
@stevejb71 I updated the exercise with your suggestion. I couldn't provide a type signature for the substitute function. The |
@@ -1,3 +1,5 @@ | |||
open Core |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
open Core.Std
instead.
Char.code
becomes Char.to_int
Char.chr
becomes Char.of_int_exn
(functions throwing exceptions are documented like this consistently in Core).
[l] | ||
else | ||
(take n l) :: (group n (drop n l)) | ||
(Core_list.take l n) :: (group n (Core_list.drop l n)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you open Core.Std, then you have List.take
and List.drop
instead.
I added a few comments to your last commit, but they are just suggestions for improvement in the non-public part of the code. Given you have the tests passing now, I'd be happy to merge if you can just add a few tests with different block sizes (I think that is important as it is on the public interface). |
3ec266d
to
22a117e
Compare
I adopted your suggestion. Even though the code is not part of the public interface, it is important to show idiomatic code. |
@stevejb71 How are these changes looking? Care to give your go on them? |
22a117e
to
e67088a
Compare
I rebased in order to incorporate the latest changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only remaining issuesl is about a test on a non standard block size. I saw a conversation about this on the canonical data, was it decided this test was not worth adding?
I opened that issue and it received not a lot of attention. The only comment was that it w as OK the way it is. That is why I did not add other tests. We could decide otherwise and still test other block sizes. @stevejb71 what do you think? |
I think we should add a test. 1 seems a bit of an edge case which would be good to test. |
I will add a test with a different block size |
Two test cases fail, but I am uncertain why. To my, even on close inspection they seem the same. But I am dyslectic, so what do I know
There is one outstanding improvement. I.e. provide type signature for substitute. I had troubles providing the correct syntax with the `function` keyword
As per @stevejb71 suggestion
e67088a
to
3bb8477
Compare
@stevejb71 added a test with a different block size |
Work in progress