Exercism v3 launches on Sept 1st 2021. Learn more! ๐Ÿš€๐Ÿš€๐Ÿš€
Avatar of rootulp

rootulp's solution

to RNA Transcription in the Elm Track

Published at Jul 13 2018 · 1 comment
Instructions
Test suite
Solution

Note:

This solution was written on an old version of Exercism. The tests below might not correspond to the solution code, and the exercise may have changed since this code was written.

Given a DNA strand, return its RNA complement (per RNA transcription).

Both DNA and RNA strands are a sequence of nucleotides.

The four nucleotides found in DNA are adenine (A), cytosine (C), guanine (G) and thymine (T).

The four nucleotides found in RNA are adenine (A), cytosine (C), guanine (G) and uracil (U).

Given a DNA strand, its transcribed RNA strand is formed by replacing each nucleotide with its complement:

  • G -> C
  • C -> G
  • T -> A
  • A -> U

Elm Installation

Refer to the Exercism help page for Elm installation and learning resources.

Writing the Code

The first time you start an exercise, you'll need to ensure you have the appropriate dependencies installed.

$ elm-package install --yes

Execute the tests with:

$ elm-test

Automatically run tests again when you save changes:

$ elm-test --watch

As you work your way through the test suite, be sure to remove the skip <| calls from each test until you get them all passing!

Source

Rosalind http://rosalind.info/problems/rna

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

Tests.elm

module Tests exposing (..)

import Expect
import RNATranscription exposing (toRNA)
import Test exposing (..)


tests : Test
tests =
    describe "RNATranscription"
        [ test "complement of cytosine is guanine" <|
            \() -> Expect.equal (Ok "G") (toRNA "C")
        , skip <|
            test "complement of guanine is cytosine" <|
                \() -> Expect.equal (Ok "C") (toRNA "G")
        , skip <|
            test "complement of thymine is adenine" <|
                \() -> Expect.equal (Ok "A") (toRNA "T")
        , skip <|
            test "complement of adenine is uracil" <|
                \() -> Expect.equal (Ok "U") (toRNA "A")
        , skip <|
            test "complement" <|
                \() -> Expect.equal (Ok "UGCACCAGAAUU") (toRNA "ACGTGGTCTTAA")
        ]

elm-package.json

{
    "version": "3.0.0",
    "summary": "Exercism problems in Elm.",
    "repository": "https://github.com/exercism/elm.git",
    "license": "BSD3",
    "source-directories": [
        ".",
        ".."
    ],
    "exposed-modules": [],
    "dependencies": {
        "elm-lang/core": "5.0.0 <= v < 6.0.0",
        "elm-community/elm-test": "4.0.0 <= v < 5.0.0"
    },
    "elm-version": "0.18.0 <= v < 0.19.0"
}
module RNATranscription exposing (..)

toRNA: String -> Result Char String
toRNA strand =
    if valid strand then
        transcribe strand
    else
        invalid strand

valid: String -> Bool
valid strand =
    strand
        |> String.toList
        |> List.all isDNANucleotide

-- It's not clear to me why the error handling tests
-- ask for the first Char in the strand
-- https://github.com/exercism/elm/issues/174
invalid: String -> Result Char String
invalid strand =
    strand
        |> String.toList
        |> List.head
        |> Maybe.withDefault 'X' -- Ideally remove this default
        |> Err

transcribe: String -> Result Char String
transcribe strand =
    strand
        |> String.map complement
        |> Ok

complement: Char -> Char
complement nucleotide =
    case nucleotide of
    'G' -> 'C'
    'C' -> 'G'
    'T' -> 'A'
    'A' -> 'U'
    _ -> 'Z' -- Ideally strongly type Nucleotide and remove this case

isDNANucleotide: Char -> Bool
isDNANucleotide nucleotide =
    List.member nucleotide ['G', 'C', 'T', 'A'] -- Ideally remove this duplication

Community comments

Find this solution interesting? Ask the author a question to learn more.
Avatar of petemcfarlane

In your complement function you mention it'd be nice to remove the _ -> 'Z' case - did you consider returning Maybe Char from this function? Then you could do _ -> Maybe.Nothing, (or return Result e Char)? You can combine the Maybe library well with List.filterMap - which takes (a -> Maybe b) and List a and returns List b.

You could maybe remove the duplicate method isDNANucleotide too, in favour of checking the list for one or more Nothings?

Just an idea!

What can you learn from this solution?

A huge amount can be learned from reading other peopleโ€™s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?