-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
443 additions
and
0 deletions.
There are no files selected for viewing
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,4 @@ | ||
*.beam | ||
*.ez | ||
build | ||
erl_crash.dump |
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,32 @@ | ||
# Help | ||
|
||
## Running the tests | ||
|
||
To run the tests, run the command `gleam test` from within the exercise directory. | ||
|
||
## Submitting your solution | ||
|
||
You can submit your solution using the `exercism submit src/dna_encoding.gleam` command. | ||
This command will upload your solution to the Exercism website and print the solution page's URL. | ||
|
||
It's possible to submit an incomplete solution which allows you to: | ||
|
||
- See how others have completed the exercise | ||
- Request help from a mentor | ||
|
||
## Need to get help? | ||
|
||
If you'd like help solving the exercise, check the following pages: | ||
|
||
- The [Gleam track's documentation](https://exercism.org/docs/tracks/gleam) | ||
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam) | ||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) | ||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) | ||
|
||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. | ||
|
||
To get help if you're having trouble, you can use one of the following resources: | ||
|
||
- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation. | ||
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel. | ||
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions. |
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,25 @@ | ||
# Hints | ||
|
||
## General | ||
|
||
- The `0b00` syntax can be used to specify an int in binary syntax rather than | ||
decimal syntax. | ||
|
||
## 1. Encode nucleic acid to binary value | ||
|
||
- The nucleotide type can be pattern matched on with a case expression. | ||
|
||
## 2. Decode the binary value to the nucleic acid | ||
|
||
- The binary int syntax can be used in patterns. | ||
- Return `Error(Nil)` if the int is is not a valid nucleotide. | ||
|
||
## 3. Encode a DNA list | ||
|
||
- The `encode_nucleotide` function can be used to encode a single nucleotide. | ||
|
||
## 4. Decode a DNA bitarray | ||
|
||
- The binary int syntax can be used within a bit array pattern. | ||
- Return `Error(Nil)` if the remaining bit array is not long enough to contain | ||
a nucleotide. |
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,157 @@ | ||
# DNA Encoding | ||
|
||
Welcome to DNA Encoding on Exercism's Gleam Track. | ||
If you need help running the tests or submitting your code, check out `HELP.md`. | ||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) | ||
|
||
## Introduction | ||
|
||
## Bit Arrays | ||
|
||
Working with binary data can be tricky, so Gleam provides a `BitArray` type and accompanying syntax to construct and to pattern match on binary data. | ||
|
||
Bit array literals are defined using the `<<>>` syntax. When defining a bit array literal, it is defined in segments. Each segment has a value and annotation, separated by a `:`. The annotation specifies how many bits will be used to encode the value, and can be omitted completely, which will default to a 8-bit integer value. | ||
|
||
```gleam | ||
// This defines a bit array with three segments of a single bit each | ||
<<0:1, 1:1, 0:1>> | ||
// This defines a bit array with three segments of 8 bits each | ||
<<0, 1, 0>> | ||
``` | ||
|
||
Specifying the type as `:1` is a shorthand for writing `:size(1)`. You need to use the longer syntax if the bit size comes from a variable. | ||
|
||
```gleam | ||
let segment_size = 1 | ||
<<0:size(segment_size), 1:size(segment_size), 0:size(segment_size)>> | ||
``` | ||
|
||
### Binary | ||
|
||
When writing binary integer literals, we can write them directly in base-2 notation by prefixing the literal with `0b`. Note that they will be displayed as decimal numbers when printed in tests or in your program. | ||
|
||
```gleam | ||
<<0b1011:4>> == <<11:4>> | ||
// -> True | ||
``` | ||
|
||
### Truncating | ||
|
||
If the value of the segment overflows the capacity of the segment's type, it will be truncated from the left. | ||
|
||
```gleam | ||
<<0b1011:3>> == <<0b0011:3>> | ||
// -> True | ||
``` | ||
|
||
### Prepending and appending | ||
|
||
You can both prepend and append to an existing bit array using the bit array syntax. The `:bits` annotation must be used for the existing bit array. | ||
|
||
```gleam | ||
let value = <<0b110:3, 0b001:3>> | ||
let new_value = <<0b011:3, value:bits, 0b000:3>> | ||
// -> <<120, 8:size(4)>> | ||
``` | ||
|
||
### Concatenating | ||
|
||
We can concatenate bit arrays stored in variables using the bit array syntax. The `:bits` annotation must be used when concatenating two bit arrays of variable sizes. | ||
|
||
```gleam | ||
let first = <<0b110:3>> | ||
let second = <<0b001:3>> | ||
let concatenated = <<first:bits, second:bits>> | ||
// -> <<49:size(6)>> | ||
``` | ||
|
||
### Pattern matching | ||
|
||
Pattern matching can also be done to obtain values from the bit array. You have to know the number of bits for each segment you want to capture, with one exception: the `:bits` annotation can be used to pattern match on a bit array of an unknown size, but this can only be used for the last segment. | ||
|
||
```gleam | ||
let assert <<value:4, rest:bits>> = <<0b01101001:8>> | ||
value == 0b0110 | ||
// -> True | ||
``` | ||
|
||
### Inspecting bit arrays | ||
|
||
~~~~exercism/note | ||
Bit arrays might be printed in a different format than the format that was used | ||
to create them. This often causes confusion when learning bit arrays. | ||
~~~~ | ||
|
||
By default, bit arrays are displayed in segments of 8 bits (a byte), even if you created them with segments of a different size. | ||
|
||
```gleam | ||
<<2011:11>> | ||
// -> <<251, 3:size(3)>> | ||
``` | ||
|
||
If you create a bit array that represents a printable UTF-8 encoded string, it may displayed as a string by functions such as `io.debug`. This is due to an implementation detail of how Gleam represents strings internally. | ||
|
||
```gleam | ||
<<>> | ||
// -> "" | ||
<<65, 66, 67>> | ||
// -> "ABC" | ||
``` | ||
|
||
## Instructions | ||
|
||
In your DNA research lab, you have been working through various ways to compress your research data to save storage space. One teammate suggests converting the DNA data to a binary representation: | ||
|
||
| Nucleic Acid | Code | | ||
| ------------ | ----- | | ||
| Adenine | `00` | | ||
| Cytosine | `01` | | ||
| Guanine | `10` | | ||
| Thymine | `11` | | ||
|
||
You ponder this, as it will potentially reduce the required data storage costs, but at the expense of human readability. You decide to write a module to encode and decode your data to benchmark your savings. | ||
|
||
## 1. Encode nucleic acid to binary value | ||
|
||
Implement `encode_nucleotide` to accept a nucleotide and return the int value of the encoded code. | ||
|
||
```gleam | ||
encode_nucleotide(Cytosine) | ||
// -> 1 | ||
// (which is equal to 0b01) | ||
``` | ||
|
||
## 2. Decode the binary value to the nucleic acid | ||
|
||
Implement `decode_nucleotide` to accept the integer value of the encoded code and return the nucleotide. | ||
|
||
```gleam | ||
decode_nucleotide(0b01) | ||
// -> Ok(Cytosine) | ||
``` | ||
|
||
## 3. Encode a DNA list | ||
|
||
Implement `encode` to accept a list of nucleotides and return a bit array of the encoded data. | ||
|
||
```gleam | ||
encode([Adenine, Cytosine, Guanine, Thymine]) | ||
// -> <<27>> | ||
``` | ||
|
||
## 4. Decode a DNA bit array | ||
|
||
Implement `decode` to accept a bit array representing nucleic acid and return the decoded data as a list of nucleotides. | ||
|
||
```gleam | ||
decode(<<27>>) | ||
// -> Ok([Adenine, Cytosine, Guanine, Thymine]) | ||
``` | ||
|
||
## Source | ||
|
||
### Created by | ||
|
||
- @lpil |
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,12 @@ | ||
name = "dna_encoding" | ||
version = "0.1.0" | ||
|
||
[dependencies] | ||
gleam_bitwise = "~> 1.2" | ||
gleam_otp = "~> 0.7 or ~> 1.0" | ||
gleam_stdlib = "~> 0.32 or ~> 1.0" | ||
simplifile = "~> 1.0" | ||
gleam_erlang = ">= 0.25.0 and < 1.0.0" | ||
|
||
[dev-dependencies] | ||
exercism_test_runner = "~> 1.4" |
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,27 @@ | ||
# This file was generated by Gleam | ||
# You typically do not need to edit this file | ||
|
||
packages = [ | ||
{ name = "argv", version = "1.0.1", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "A6E9009E50BBE863EB37D963E4315398D41A3D87D0075480FC244125808F964A" }, | ||
{ name = "exercism_test_runner", version = "1.7.0", build_tools = ["gleam"], requirements = ["argv", "gap", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_stdlib", "simplifile"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "2FC1BADB19BEC2AE77BFD2D3A606A014C85412A7B874CAFC4BA8CF04B0B257CD" }, | ||
{ name = "gap", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "2EE1B0A17E85CF73A0C1D29DA315A2699117A8F549C8E8D89FA8261BE41EDEB1" }, | ||
{ name = "glance", version = "0.8.2", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "ACF09457E8B564AD7A0D823DAFDD326F58263C01ACB0D432A9BEFDEDD1DA8E73" }, | ||
{ name = "gleam_bitwise", version = "1.3.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "B36E1D3188D7F594C7FD4F43D0D2CE17561DE896202017548578B16FE1FE9EFC" }, | ||
{ name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, | ||
{ name = "gleam_community_colour", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "A49A5E3AE8B637A5ACBA80ECB9B1AFE89FD3D5351FF6410A42B84F666D40D7D5" }, | ||
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, | ||
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, | ||
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, | ||
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, | ||
{ name = "glexer", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "4484942A465482A0A100936E1E5F12314DB4B5AC0D87575A7B9E9062090B96BE" }, | ||
{ name = "simplifile", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "EB9AA8E65E5C1E3E0FDCFC81BC363FD433CB122D7D062750FFDF24DE4AC40116" }, | ||
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, | ||
] | ||
|
||
[requirements] | ||
exercism_test_runner = { version = "~> 1.4" } | ||
gleam_bitwise = { version = "~> 1.2" } | ||
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0"} | ||
gleam_otp = { version = "~> 0.7 or ~> 1.0" } | ||
gleam_stdlib = { version = "~> 0.32 or ~> 1.0" } | ||
simplifile = { version = "~> 1.0" } |
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,47 @@ | ||
import gleam/list | ||
import gleam/result | ||
|
||
pub type Nucleotide { | ||
Adenine | ||
Cytosine | ||
Guanine | ||
Thymine | ||
} | ||
|
||
pub fn encode_nucleotide(nucleotide: Nucleotide) -> Int { | ||
case nucleotide { | ||
Adenine -> 0b00 | ||
Cytosine -> 0b01 | ||
Guanine -> 0b10 | ||
Thymine -> 0b11 | ||
} | ||
} | ||
|
||
pub fn decode_nucleotide(nucleotide: Int) -> Result(Nucleotide, Nil) { | ||
case nucleotide { | ||
0b00 -> Ok(Adenine) | ||
0b01 -> Ok(Cytosine) | ||
0b10 -> Ok(Guanine) | ||
0b11 -> Ok(Thymine) | ||
_ -> Error(Nil) | ||
} | ||
} | ||
|
||
pub fn encode(dna: List(Nucleotide)) -> BitArray { | ||
list.fold(dna, <<>>, fn(acc, nucleotide) { | ||
<<acc:bits, encode_nucleotide(nucleotide):2>> | ||
}) | ||
} | ||
|
||
pub fn decode(dna: BitArray) -> Result(List(Nucleotide), Nil) { | ||
decode_iter(dna, []) | ||
} | ||
|
||
fn decode_iter(dna: BitArray, decoded: List(Result(Nucleotide, Nil))) { | ||
case dna { | ||
<<>> -> result.all(decoded) | ||
<<value:2, rest:bits>> -> | ||
decode_iter(rest, list.append(decoded, [decode_nucleotide(value)])) | ||
_ -> Error(Nil) | ||
} | ||
} |
Oops, something went wrong.