-
-
Notifications
You must be signed in to change notification settings - Fork 194
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add approach: validate first, then transcribe
- Loading branch information
1 parent
41c53b3
commit eaf8011
Showing
3 changed files
with
80 additions
and
0 deletions.
There are no files selected for viewing
18 changes: 18 additions & 0 deletions
18
exercises/practice/rna-transcription/.approaches/config.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"introduction": { | ||
"authors": [ | ||
"MatthijsBlom" | ||
] | ||
}, | ||
"approaches": [ | ||
{ | ||
"uuid": "209cd027-6f98-47ac-a77f-8a083e0cd100", | ||
"slug": "validate-first", | ||
"title": "Validate first, then transcribe", | ||
"blurb": "First, find out whether there are invalid characters in the input. Then, if there aren't, transcribe the strand in one go.", | ||
"authors": [ | ||
"MatthijsBlom" | ||
] | ||
} | ||
] | ||
} |
54 changes: 54 additions & 0 deletions
54
exercises/practice/rna-transcription/.approaches/validate-first/content.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Validate first, then transcribe | ||
|
||
```haskell | ||
toRNA :: String -> Either Char String | ||
toRNA dna = | ||
case find (`notElem` "GCTA") dna of | ||
Nothing -> Right (map transcribe dna) | ||
Just c -> Left c | ||
where | ||
transcribe = \case | ||
'G' -> 'C' | ||
'C' -> 'G' | ||
'T' -> 'A' | ||
'A' -> 'U' | ||
``` | ||
|
||
One approach to solving this problem is to | ||
|
||
- first check that all input characters are valid, | ||
- return one of the invalid characters if there are any, and otherwise to | ||
- convert all the DNA nucleotides into RNA nucleotides. | ||
|
||
Some submitted solutions retrieve the invalid character (if present) in two steps: | ||
|
||
- first check that there are _some_ invalid characters, for example using `any`, and | ||
- then find the first one, for example using `filter` and `head`. | ||
|
||
The solution highlighted here combines these steps into one. | ||
As used here, `find` returns `Nothing` if there are no invalid characters, and if there are then it returns `Just` the first one. | ||
By pattern matching on `find`'s result it is determined how to proceed. | ||
|
||
For transcribing DNA nucleobases into RNA nucleobases a locally defined function `transcribe` is used. | ||
It is a [partial function][wiki-partial-functions]: when given any character other than `'G'`, `'C'`, `'T'`, or `'A'` it will crash. | ||
|
||
Partial functions display behavior (e.g. crashing) that is not documented in their types. | ||
This tends to make reasoning about code that uses them more difficult. | ||
For this reason, partial functions are generally to be avoided. | ||
|
||
Partiality is less objectionable in local functions than in global ones, because in local contexts it is easier to make sure that functions are never applied to problematic arguments. | ||
Indeed, in the solution highlighted above it is clear that `transcribe` will never be applied to a problematic character, as if there were any such characters in `dna` then `find` would have returned `Just _` and not `Nothing`. | ||
|
||
Still, it would be nice if it weren't necessary to check that `transcribe` is never applied to invalid characters. | ||
`transcribe` is forced by its `Char -> Char` type to either be partial or else to return bogus values for some inputs – which would be similarly undesirable. | ||
But another type, such as `Char -> Maybe Char`, would allow `transcribe` to be total. | ||
The other approaches use such a variant. | ||
|
||
This approach has the input walked twice (or thrice). | ||
It is possible to solve this problem by walking the input only once. | ||
The other approaches illustrate how. | ||
|
||
|
||
[wiki-partial-functions]: | ||
https://wiki.haskell.org/Partial_functions | ||
"Haskell Wiki: Partial functions" |
8 changes: 8 additions & 0 deletions
8
exercises/practice/rna-transcription/.approaches/validate-first/snippet.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
toRNA :: String -> Either Char String | ||
toRNA dna = | ||
case find (`notElem` "GCTA") dna of | ||
Nothing -> Right (map transcribe dna) | ||
Just c -> Left c | ||
where | ||
transcribe = \case | ||
'G' -> 'C' |