exercism / unison

Exercism exercises in Unison.
https://exercism.org/tracks/unison
MIT License
3 stars 19 forks source link

Building a training set of tags for unison #102

Closed ErikSchierboom closed 11 months ago

ErikSchierboom commented 1 year ago

Hello lovely maintainers :wave:

We've recently added "tags" to student's solutions. These express the constructs, paradigms and techniques that a solution uses. We are going to be using these tags for lots of things including filtering, pointing a student to alternative approaches, and much more.

In order to do this, we've built out a full AST-based tagger in C#, which has allowed us to do things like detect recursion or bit shifting. We've set things up so other tracks can do the same for their languages, but its a lot of work, and we've determined that actually it may be unnecessary. Instead we think that we can use machine learning to achieve tagging with good enough results. We've fine-tuned a model that can determine the correct tags for C# from the examples with a high success rate. It's also doing reasonably well in an untrained state for other languages. We think that with only a few examples per language, we can potentially get some quite good results, and that we can then refine things further as we go.

I released a new video on the Insiders page that talks through this in more detail.

We're going to be adding a fully-fledged UI in the coming weeks that allow maintainers and mentors to tag solutions and create training sets for the neural networks, but to start with, we're hoping you would be willing to manually tag 20 solutions for this track. In this post we'll add 20 comments, each with a student's solution, and the tags our model has generated. Your mission (should you choose to accept it) is to edit the tags on each issue, removing any incorrect ones, and add any that are missing. In order to build one model that performs well across languages, it's best if you stick as closely as possible to the C# tags as you can. Those are listed here. If you want to add extra tags, that's totally fine, but please don't arbitrarily reword existing tags, even if you don't like what Erik's chosen, as it'll just make it less likely that your language gets the correct tags assigned by the neural network.


To summarise - there are two paths forward for this issue:

  1. You're up for helping: Add a comment saying you're up for helping. Update the tags some time in the next few days. Add a comment when you're done. We'll then add them to our training set and move forward.
  2. You not up for helping: No problem! Just please add a comment letting us know :)

If you tell us you're not able/wanting to help or there's no comment added, we'll automatically crowd-source this in a week or so.

Finally, if you have questions or want to discuss things, it would be best done on the forum, so the knowledge can be shared across all maintainers in all tracks.

Thanks for your help! :blue_heart:


Note: Meta discussion on the forum

ErikSchierboom commented 1 year ago

Exercise: rna-transcription

Code

toRNA : Text -> Optional Text
toRNA dna = toRNA.recursive [] (toCharList dna)

toRNA.recursive : [Char] -> [Char] -> Optional Text
toRNA.recursive a =
    cases 
        [] -> Some (fromCharList a)
        h +: t -> 
            match toRNA.mapChar h with
                Some c -> toRNA.recursive (a :+ c) t
                Optional.None -> None
        _ -> None

toRNA.mapChar : Char -> Optional Char
toRNA.mapChar =
    cases 
        x
            | x == ?G -> Some ?C
            | x == ?C -> Some ?G
            | x == ?T -> Some ?A
            | x == ?A -> Some ?U
        _ -> None 

> toRNA "C"

Tags:

construct:add
construct:char
construct:constructor
construct:function
construct:invocation
construct:lambda
construct:list
construct:match
construct:named-argument
construct:optional-type
construct:parameter
construct:pattern-matching
construct:recursion
construct:string
construct:underscore
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:higher-order-functions
technique:recursion
ErikSchierboom commented 1 year ago

Exercise: run-length-encoding

Code

encode : Text -> Text
encode input =
  render : (Optional (Char, Nat)) -> Text
  render = cases
    Some (c, count) ->
      if count == 1 then toText c
      else toText count ++ toText c
    None -> ""
  go = cases
    (textOut, s @ (Some (prevC, count))), c ->
      if prevC === c then (textOut, Some (c, increment count))
      else (textOut ++ (render s), (Some (c, 1)))
    (textOut, None), c -> (textOut, Some (c, 1))
  match List.foldLeft go ("", None) (toCharList input) with
    (acc, remainder) -> acc ++ (render remainder)

decode : Text -> Text
decode input =
  go = cases
    (output, digits), c ->
      if isDigit c then (output, digits :+ c)
      else
        count = match digits with
          [] -> 1
          _ -> getOrBug "oops" (Nat.fromText (Text.fromCharList digits))
        textToAdd = Text.repeat count (toText c)
        (output ++ textToAdd, [])
  List.foldLeft go ("", []) (toCharList input) |> at1

Tags:

construct:==
construct:==⁼
construct:@
construct:char
construct:constructor
construct:if
construct:if-then-else
construct:infix-function
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:list
construct:match
construct:nat
construct:number
construct:parameter
construct:pattern-matching
construct:text
construct:then-expression
construct:tuple
construct:underscore
construct:variable
paradigm:functional
paradigm:object-oriented
technique:higher-order-functions
technique:type-extensions
uses:List
ErikSchierboom commented 1 year ago

Exercise: run-length-encoding

Code

encode : Text -> Text
encode input =
  go acc = cases
    [] -> (acc, "")
    hd +: tl -> 
      front = takeWhile (e -> hd === e) tl
      fTlLen = size front
      if fTlLen == 0 then
        go (acc ++ Char.toText hd) tl
      else
        go (acc ++ toText (fTlLen + 1) ++ (Char.toText hd)) (drop fTlLen tl)
  at1 (go "" (toCharList input))

decode : Text -> Text
decode input =
  go acc = cases
    [] -> acc
    charList ->
      match takeWhile isDigit charList with
        [] -> match charList with
          [] -> bug (Generic.failure "Should not come here") 
          hd +: tl -> go (acc ++ toText hd) tl
        digits -> 
          rep = fromCharList digits |> fromText |> getOrBug "Not a digit"
          match drop (size digits) charList with
            [] -> bug (Generic.failure "Should not come here")
            hd +: tl -> go (acc Text.++ (repeat rep (Char.toText hd))) tl
  go "" (toCharList input)

Tags:

construct:add
construct:boolean
construct:char
construct:if-then-else
construct:implicit-conversion
construct:invocation
construct:lambda
construct:list
construct:local-binding
construct:match
construct:number
construct:parameter
construct:pattern-matching
construct:recursion
construct:string
construct:text
construct:then-expression
construct:using-recursion
construct:variable-shadowing
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
ErikSchierboom commented 1 year ago

Exercise: all-your-base

Code

use Int / toText *
use List +: size replace at at! foldRight

rebase : Int -> [Int] -> Int -> Optional [Int]
rebase inputBase inputDigits outputBase = 
   folder digit = if (digit < +0) || (digit >= inputBase) then abort else cases (acc, mult) ->
      (acc + (digit * mult), mult * inputBase)

   total = 'let
     foldRight folder (+0, +1) inputDigits

   go acc n = 
       if n <= +0 then acc
        else m = (mod n outputBase)
             d = (n / outputBase)
             go (m +: acc) d

   result = 'let
     if (inputBase <= +1) || (outputBase <= +1) then abort else ()
     result' = let go [] (at1 !total) 
     if (size result') === 0 then [+0]
     else result'
   !(toOptional result)

Tags:

construct:add
construct:boolean
construct:divide
construct:if-then-else
construct:implicit-conversion
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:list
construct:logical-or
construct:multiply
construct:number
construct:parameter
construct:pattern-matching
construct:recursion
construct:string
construct:subtract
construct:tuple
construct:underscore
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:logical
paradigm:object-oriented
technique:boolean-logic
technique:higher-order-functions
technique:looping
technique:recursion
ErikSchierboom commented 1 year ago

Exercise: all-your-base

Code

fromDigits : Int -> [Int] -> Int
fromDigits base digits =
    reverse digits
        |> mapIndexed (idx d -> (pow base idx) * d)
        |> foldLeft (Int.+) +0

toDigits : Int -> Int -> [Int]
toDigits base nr =
    go : [Int] -> Int -> [Int]
    go digits = cases
        +0 -> digits
        nr -> 
            digit = mod nr base
            go (digit +: digits) (div nr base)
    if nr == +0 then [+0] else go [] nr

rebase : Int -> [Int] -> Int -> Optional [Int]
rebase inputBase inputDigits outputBase = 
    baseValid b = b > +1
    digitValid d = (d >= +0) && (d < inputBase)
    digitsValid digits = digits |> List.all digitValid
    if baseValid inputBase && baseValid outputBase && digitsValid inputDigits then
        number = fromDigits inputBase inputDigits
        Some (toDigits outputBase number)
    else
        None

Tags:

construct:add
construct:boolean
construct:cases
construct:divide
construct:double
construct:eq
construct:floating-point-number
construct:function
construct:if-then-else
construct:implicit-conversion
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:list
construct:local-binding
construct:logical-and
construct:map
construct:multiply
construct:number
construct:optional-type
construct:parameter
construct:pattern-matching
construct:recursion
construct:reverse
construct:using-recursion
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:higher-order-functions
technique:looping
technique:recursion
uses:List
ErikSchierboom commented 1 year ago

Exercise: collatz-conjecture

Code

use Nat / increment

steps : Nat -> Optional Nat
steps n =
  next n = if (mod n 2) === 0 then n / 2 else (3 * n) + 1
  go count = cases
     0 -> None
     1 -> Some count
     n -> go (increment count) (next n)
  go 0 n

Tags:

construct:add
construct:boolean
construct:cases
construct:divide
construct:else
construct:if-then-else
construct:invocation
construct:lambda
construct:multiply
construct:nat
construct:number
construct:optional-type
construct:parameter
construct:pattern-matching
construct:recursion
construct:subtract
construct:then
construct:variable
paradigm:functional
technique:higher-order-functions
technique:recursion
ErikSchierboom commented 1 year ago

Exercise: simple-linked-list

Code

structural type LinkedList a = Nil | Cons a (LinkedList a)

LinkedList.new : a -> LinkedList a
LinkedList.new a = Cons a Nil

LinkedList.cons : a -> LinkedList a -> LinkedList a
LinkedList.cons a ls = Cons a ls 

LinkedList.nil : LinkedList a
LinkedList.nil = Nil 

LinkedList.fromList : [a] -> LinkedList a
LinkedList.fromList = foldRight Cons Nil

LinkedList.head : LinkedList a -> Optional a
LinkedList.head = cases 
  Nil -> None
  Cons h _ -> Some h 

LinkedList.isNil : LinkedList a -> Boolean
LinkedList.isNil = cases
  Nil -> true
  _ -> false

LinkedList.tail : LinkedList a -> LinkedList a
LinkedList.tail = cases
  Nil -> Nil
  Cons _ tl -> tl

LinkedList.reverseLinkedList : LinkedList a -> LinkedList a
LinkedList.reverseLinkedList = toList >> List.reverse >> fromList

LinkedList.toList : LinkedList a -> [a]
LinkedList.toList l = 
  go acc = cases
    Nil      -> acc
    Cons h t -> go (acc :+ h) t
  go [] l

Tags:

construct:application
construct:boolean
construct:cases
construct:constructor
construct:function
construct:method
construct:parameter
construct:pattern-matching
construct:recursive-function
construct:string
construct:tagged-union
construct:to-list
construct:using-recursion
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:higher-order-functions
technique:looping
technique:recursion
uses:List.reverse
ErikSchierboom commented 1 year ago

Exercise: space-age

Code

age : Text -> Nat -> Optional Float
age planet earthAgeSeconds =
  use Nat toFloat
  earthAgeYears = (toFloat earthAgeSeconds) / 31557600.0
  match planet with
    "Mercury" -> Some(earthAgeYears / 0.2408467)
    "Venus" -> Some(earthAgeYears / 0.61519726)
    "Earth" -> Some earthAgeYears
    "Mars" -> Some(earthAgeYears / 1.8808158)
    "Jupiter" -> Some(earthAgeYears / 11.862615)
    "Saturn" -> Some(earthAgeYears / 29.447498)
    "Uranus" -> Some(earthAgeYears / 84.016846)
    "Neptune" -> Some(earthAgeYears / 164.79132)
    _ -> None

Tags:

construct:divide
construct:floating-point-number
construct:invocation
construct:lambda
construct:match
construct:optional-type
construct:parameter
construct:pattern-matching
construct:text
construct:use
construct:variable
paradigm:functional
technique:higher-order-functions
ErikSchierboom commented 1 year ago

Exercise: space-age

Code

planets = Map.fromList [
  ("Mercury", 0.2408467),
  ("Venus", 0.61519726),
  ("Earth", 1.0),
  ("Mars", 1.8808158),
  ("Jupiter", 11.862615),
  ("Saturn", 29.447498),
  ("Uranus", 84.016846),
  ("Neptune", 164.79132)
]

age : Text -> Nat -> Optional Float
age planet earthAgeSeconds =
  convert factor =
    (Nat.toFloat earthAgeSeconds) / factor / 31557600.0
  Optional.map convert (Map.get planet planets)

Tags:

construct:divide
construct:double
construct:floating-point-number
construct:identifier
construct:implicit-conversion
construct:lambda
construct:list
construct:map
construct:number
construct:parameter
construct:pattern-matching
construct:text
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
uses:Map
ErikSchierboom commented 1 year ago

Exercise: armstrong-numbers

Code

use Nat / mod + >
use List foldLeft

isArmstrongNumber : Nat -> Boolean
isArmstrongNumber number =
  toDigits: [Nat] -> Nat -> [Nat]
  toDigits acc n = 
     m = mod n 10
     d = n / 10
     n' = acc :+ m

     if d > 0 then toDigits n' d else n'

  digits = toDigits [] number
  number' = foldLeft (ns -> n -> ns + (pow n (size digits))) 0 digits
  number === number'

Tags:

construct:add
construct:boolean
construct:divide
construct:double
construct:else
construct:eq
construct:floating-point-number
construct:if-then-else
construct:implicit-conversion
construct:invocation
construct:lambda
construct:list
construct:local-binding
construct:number
construct:parameter
construct:pattern-matching
construct:recursion
construct:ternary
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:higher-order-functions
technique:looping
technique:math
ErikSchierboom commented 1 year ago

Exercise: allergies

Code

allergens : [Text]
allergens = ["eggs", "peanuts", "shellfish", "strawberries", "tomatoes", "chocolate", "pollen", "cats"]

allergies.allergicTo : Text -> Nat -> Boolean
allergies.allergicTo allergen score =
  allergens
    |> indexOf allergen
    |> map (idx -> isSetBit idx score)
    |> getOrElse false

allergies.list : Nat -> [Text]
allergies.list score = filter (allergen -> allergicTo allergen score) allergens

Tags:

construct:application
construct:boolean
construct:define
construct:function
construct:invocation
construct:lambda
construct:list
construct:method
construct:parameter
construct:pipeline
construct:set
construct:string
construct:variable
paradigm:functional
technique:functional-composition
uses:List
ErikSchierboom commented 1 year ago

Exercise: spiral-matrix

Code

-- This recursive solution draws a single row of the matrix
-- then draws a rotated spiral matrix below it.
-- We use `reverse` because transpose rotates counterclockwise
-- and we want clockwise
spiralMatrix : Nat -> [[Nat]]
spiralMatrix n = 
  spiral' = cases
    0, _, _ -> []
    x, y, offset -> 
      List.rangeClosed (offset + 1) (offset + x) 
        +: map reverse (transpose (spiral' (y - 1) x (offset + x)))
  spiral' n n 0

-- `transpose` swaps the rows and columns of a matrix,
-- which has the effect of rotating it counterclockwise.
-- E.g. > transpose [[1, 2, 3],
--                   [4, 5, 6],
--                   [7, 8, 9]]
--          ⧩
--                  [[1, 4, 7],
--                   [2, 5, 8],
--                   [3, 6, 9]]
transpose : [[a]] -> [[a]]
transpose = cases
  [] -> []
  [] +: xss -> transpose xss
  ((x +: xs) +: xss) -> 
    ((hds, tls)) = unzip let Each.toList 'let
      (hd +: tl) = each xss
      (hd, tl)
    combine y h ys t = (y List.+: h) List.+: transpose (ys List.+: t)
    combine x hds xs tls

-- Turns a list of pairs into a pair of lists
unzip : [(a,b)] -> ([a], [b])
unzip = cases
  [] -> ([], [])
  ((a,b) +: xs) ->
    ((as, bs)) = unzip xs
    (a +: as, b +: bs)

Tags:

construct:add
construct:assignment
construct:char
construct:comment
construct:constructor
construct:expression
construct:function
construct:invocation
construct:lambda
construct:let
construct:list
construct:nat
construct:number
construct:parameter
construct:pattern-matching
construct:recursion
construct:string
construct:subtract
construct:tuple
construct:underscore
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:lambda
technique:higher-order-functions
technique:recursion
ErikSchierboom commented 1 year ago

Exercise: scale-generator

Code

use List foldLeft 

unique type Chromatic = A | As | B | C | Cs | D | Ds | E | F | Fs | G | Gs

Chromatic.toSharpText = cases
  A -> "A"
  As -> "A#"
  B -> "B"
  C -> "C"
  Cs -> "C#"
  D -> "D"
  Ds -> "D#"
  E -> "E"
  F -> "F"
  Fs -> "F#"
  G -> "G"
  Gs -> "G#"

Chromatic.toFlatText = cases
  A -> "A"
  As -> "Bb"
  B -> "B"
  C -> "C"
  Cs -> "Db"
  D -> "D"
  Ds -> "Eb"
  E -> "E"
  F -> "F"
  Fs -> "Gb"
  G -> "G"
  Gs -> "Ab"

Chromatic.halfStep = cases
  A -> As
  As -> B
  B -> C
  C -> Cs
  Cs -> D
  D -> Ds
  Ds -> E
  E -> F
  F -> Fs
  Fs -> G
  G -> Gs
  Gs -> A

Chromatic.wholeStep = cases
  A -> B
  As -> C
  B -> Cs
  C -> D
  Cs -> Ds
  D -> E
  Ds -> F
  E -> Fs
  F -> G
  Fs -> Gs
  G -> A
  Gs -> As

starting: Text ->  (Boolean, Chromatic)
starting = cases
  "C" -> (true, C)
  "a" -> (true, A)
  "G" -> (true, G)
  "D" -> (true, D)
  "E" -> (true, E)
  "A" -> (true, A)
  "G" -> (true, G)
  "F#" -> (true, Fs)
  "e" -> (true, E)
  "b" -> (true, B)
  "f#" -> (true, Fs)
  "c#" -> (true, Cs)
  "g#" -> (true, Gs)
  "d#" -> (true, Ds)
  "F" -> (false, F)
  "Bb" -> (false, As)
  "Eb" -> (false, Ds)
  "Ab" -> (false, Gs)
  "Db" -> (false, Cs)
  "Gb" -> (false, Fs)
  "d" -> (false, D)
  "g" -> (false, G)
  "c" -> (false, G)
  "f" -> (false, F)
  "bb" -> (false, As)
  "eb" -> (false, Ds)

interval : Text -> Text -> [Text]
interval tonal pattern =
  (sharp, start) = starting tonal
  sharpFlat = if sharp then toSharpText else toFlatText
  fold = cases (acc, c) -> cases
     ?M -> ((acc :+ c), (wholeStep c))
     ?A -> ((acc :+ c), (halfStep (wholeStep c)))
     _  -> ((acc :+ c), halfStep c)
  tones = foldLeft fold ([], start) (toCharList pattern) |> at1

  map sharpFlat (tones :+ start)

chromatic : Text -> [Text]
chromatic start = match interval start "mmmmmmmmmmmm" with notes :+ _ -> notes

Tags:

construct:assignment
construct:boolean
construct:char
construct:constructor
construct:if-then-else
construct:invocation
construct:lambda
construct:list
construct:match
construct:parameter
construct:pattern
construct:pipe
construct:text
construct:tuple
construct:type
construct:use
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
ErikSchierboom commented 1 year ago

Exercise: bowling

Code

{{ This type is used to capture the expected error message }}
unique type Error = Error Text

{{ This is all the states a frame could be in:

   BallOne - new frame, no balls rolled yet
   BallTwo n - second ball, first was n (0 <= n < 10)
   Spare - Two balls totalling 10 have been rolled
   Strike - One ball totalling 10 has been rolled
   Strike1 n - Strike was rolled, since there was one ball with n pins
   Complete n - Frame is complete and scored n
}}
unique type Frame =
  BallOne |
  BallTwo Nat |
  Spare |
  Strike |
  Strike1 Nat |
  Complete Nat

{{ This tracks the current state of the game }}
unique type GameState = {
  completedFrames: Nat,
  currentScore: Nat,
  currentFrame: Optional Frame,
  activeFrames: [Frame]
}

{{ useful for debugging }}
Frame.toText = cases
  BallOne -> "BallOne"
  BallTwo n -> "BallTwo(" ++ (Nat.toText n) ++ ")"
  Spare -> "Spare"
  Strike -> "Strike"
  Strike1 n -> "Strike1(" ++ (Nat.toText n) ++ ")"
  Complete n -> "Complete(" ++ (Nat.toText n) ++ ")"

Frame.toTextO = cases
  None -> "None"
  Some f -> Frame.toText f

GameState.toText = cases
  GameState complete score current active -> (Nat.toText complete) ++ " frames complete, Current Score: " ++ (Nat.toText score) ++ "Current Frame: " ++ (Frame.toTextO current) ++ " Active: " ++ (List.foldLeft (acc -> s -> acc  ++ " " ++ (Frame.toText s)) "" active)

{{ given the next ball in the sequence, what is the next state of this frame }}
Frame.nextBall n = cases
  BallOne -> if n === 10 then Strike else BallTwo n
  BallTwo m | n + m === 10 -> Spare
  BallTwo m -> Complete (n + m)
  Spare -> Complete (n + 10)
  Strike -> Strike1 n
  Strike1 m -> Complete (10 + m  + n)

{{ should this frame remain the current frame }}
Frame.active = cases
  Spare -> false
  Strike -> false
  Strike1 _ -> false
  Complete _ -> false
  _ -> true

{{ given the next ball, update the state of the current frame }}
GameState.updateCurrent: Nat -> GameState -> GameState
GameState.updateCurrent n = cases
  GameState count c None fs -> GameState count c None fs
  GameState count c (Some f) fs ->
    match Frame.nextBall n f with
      Complete s ->
        if count == 9 then GameState 10 (c + s) None fs
                      else GameState (increment count) (c + s) (Some BallOne) fs

      f' | active f' -> GameState count c (Some f') fs
      f' ->
        if count == 9 then GameState 10 c None (fs :+ f')
                      else GameState (increment count) c (Some BallOne) (fs :+ f')

{{ given the next ball, update the state of the active frames other than current frame }}
GameState.updateActive: Nat -> GameState -> GameState
GameState.updateActive n = cases GameState count c f as ->
  go score acc = cases
    [] -> GameState count (c+score) f acc
    h +: t -> match Frame.nextBall n h with
      Complete s -> go (score + s) acc t
      h -> go score (acc :+ h) t

  go 0 [] as

{{ given a current state and the next ball, what is the next state }}
GameState.next:  Nat -> GameState -> GameState
GameState.next n s = updateActive n s |> updateCurrent n
GameState.new = GameState 0 0 (Some BallOne) []

score : [Nat] -> Either Error Nat
score rolls =
  match List.foldRight GameState.next GameState.new (reverse rolls) with
    GameState 10 n _ [] -> Right n
    n -> Left (Error "Score cannot be taken until the end of the game")

Tags:

construct:add
construct:boolean
construct:cases
construct:comment
construct:constructor
construct:curried-function
construct:custom-type
construct:definition-site
construct:else
construct:if-expression
construct:implicit-conversion
construct:invocation
construct:lambda
construct:list
construct:match-expression
construct:nat
construct:number
construct:optional-type
construct:parameter
construct:pattern
construct:record
construct:string
construct:then
construct:type-alias
construct:union-type
construct:unique-type
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:higher-order-functions
technique:recursion
uses:List
ErikSchierboom commented 1 year ago

Exercise: sieve

Code

use List +:
use Nat ==

sieve.primes : Nat -> [Nat]
sieve.primes n = Stream.toList! <| do sieve.stream (List.rangeClosed 2 n)

sieve.stream : [Nat] -> { Stream Nat } ()
sieve.stream xs =
  match xs with
    [] -> ()
    (x +: xs) ->
      sieved = sieve.removeMultiples x xs
      Stream.emit x
      sieve.stream sieved

sieve.removeMultiples : Nat -> [Nat] -> [Nat]
sieve.removeMultiples a xs =
  go : Nat -> Nat -> [Nat] -> [Nat]
  go a b xs =
    match xs with
      [] -> []
      (y +: ys) ->
        if b == y then
          go a (a+b) ys
        else
          if b < y then
            go a (a+b) xs
          else
            y +: go a b ys
  go a a xs

Tags:

construct:add
construct:assignment
construct:do
construct:function
construct:if-then-else
construct:invocation
construct:lambda
construct:let
construct:list
construct:match
construct:nat
construct:number
construct:parameter
construct:pattern-matching
construct:recursion
construct:stream
construct:tuple
construct:variable-shadowing
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
technique:laziness
technique:looping
technique:recursion
uses:List
uses:Stream
ErikSchierboom commented 1 year ago

Exercise: protein-translation

Code

proteinTranslation.translate : [Text] -> [Text] -> {Exception} [Text]
proteinTranslation.translate proteins codons = match codons with
    []                                                                         -> proteins
    c +: cs | (c === "UAA") || (c === "UAG") || (c === "UGA")                  -> proteins
            | (c === "AUG")                                                    -> translate (proteins :+ "Methionine") cs
            | (c === "UUU") || (c === "UUC")                                   -> translate (proteins :+ "Phenylalanine") cs
            | (c === "UUA") || (c === "UUG")                                   -> translate (proteins :+ "Leucine") cs
            | (c === "UCU") || (c === "UCC") || (c === "UCA") || (c === "UCG") -> translate (proteins :+ "Serine") cs
            | (c === "UAU") || (c === "UAC")                                   -> translate (proteins :+ "Tyrosine") cs
            | (c === "UGU") || (c === "UGC")                                   -> translate (proteins :+ "Cysteine") cs
            | (c === "UGG")                                                    -> translate (proteins :+ "Tryptophan") cs
    c +: cs                                                                    -> Exception.raise(Generic.failure "Unknown codon" c)

proteinTranslation.proteins : Text -> [Text]
proteinTranslation.proteins rna = Exception.unsafeRun! '((Text.chunk 3 >> translate []) rna)

Tags:

construct:add
construct:boolean
construct:char
construct:constructor
construct:function
construct:invocation
construct:lambda
construct:list
construct:logical-or
construct:match
construct:number
construct:parameter
construct:pattern
construct:recursive-call
construct:string
construct:throw
construct:using-directives
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:boolean-logic
technique:exceptions
technique:higher-order-functions
technique:recursion
ErikSchierboom commented 1 year ago

Exercise: protein-translation

Code

proteinTranslation.proteins : Text -> [Text]
proteinTranslation.proteins rna =
    translate codon = match codon with
        "AUG" -> "Methionine"
        "UGG" -> "Tryptophan"
        c | (c == "UUU") || (c == "UUC") -> "Phenylalanine"
        c | (c == "UUA") || (c == "UUG") -> "Leucine"
        c | (c == "UCU") || (c == "UCC") || (c == "UCA") || (c == "UCG") -> "Serine"
        c | (c == "UAU") || (c == "UAC") -> "Tyrosine"
        c | (c == "UGU") || (c == "UGC") -> "Cysteine"
        _ -> "STOP"

    takeWhile (p -> p != "STOP") <| map translate (Text.chunk 3 rna)

Tags:

construct:boolean
construct:char
construct:expression
construct:function
construct:invocation
construct:lambda
construct:list
construct:map
construct:match
construct:number
construct:parameter
construct:pattern-matching
construct:string
construct:takeWhile
construct:text
construct:using-directives
construct:visibility-modifiers
paradigm:functional
technique:higher-order-functions
uses:List
uses:Text
ErikSchierboom commented 1 year ago

Exercise: difference-of-squares

Code

differenceOfSquares.square : Nat -> Nat
differenceOfSquares.square n = n * n

differenceOfSquares.squareOfSum : Nat -> Nat
differenceOfSquares.squareOfSum number =
  List.rangeClosed 1 number |> sum |> square

differenceOfSquares.sumOfSquares : Nat -> Nat
differenceOfSquares.sumOfSquares number =
  List.rangeClosed 1 number |> List.map square |> sum

differenceOfSquares.difference : Nat -> Nat
differenceOfSquares.difference number =
  squareOfSum number - sumOfSquares number

Tags:

construct:application
construct:binding
construct:subtract
construct:function
construct:invocation
construct:lambda
construct:list
construct:multiply
construct:number
construct:parameter
construct:pattern-matching
construct:pipe-forward
construct:subtract
construct:variable
paradigm:functional
technique:higher-order-functions
ErikSchierboom commented 1 year ago

Exercise: roman-numerals

Code

romanNumerals.toRoman : Nat -> Text
romanNumerals.toRoman = toRomanAcc []

use List +:

romanNumerals.toRomanAcc : [Text] -> Nat -> Text
romanNumerals.toRomanAcc acc decimal = match decimal with
  x
    | x >= 1000 -> toRomanAcc ("M" +: acc) (x - 1000)
    | x >= 900 -> toRomanAcc ("CM" +: acc) (x - 900)
    | x >= 500 -> toRomanAcc ("D" +: acc) (x - 500)
    | x >= 400 -> toRomanAcc ("CD" +: acc) (x - 400)
    | x >= 100 -> toRomanAcc ("C" +: acc) (x - 100)
    | x >= 90 -> toRomanAcc ("XC" +: acc) (x - 90)
    | x >= 50 -> toRomanAcc ("L" +: acc) (x - 50)
    | x >= 40 -> toRomanAcc ("XL" +: acc) (x - 40)
    | x >= 10 -> toRomanAcc ("X" +: acc) (x - 10)
    | x >= 9 -> toRomanAcc ("IX" +: acc) (x - 9)
    | x >= 5 -> toRomanAcc ("V" +: acc) (x - 5)
    | x >= 4 -> toRomanAcc ("IV" +: acc) (x - 4)
    | x >= 1 -> toRomanAcc ("I" +: acc) (x - 1)
  _ -> join "" (reverse acc)

Tags:

construct:add
construct:char
construct:constructor
construct:function
construct:invocation
construct:lambda
construct:list
construct:match
construct:nat
construct:number
construct:parameter
construct:pattern-matching
construct:recursion
construct:string
construct:subtract
construct:text
construct:underscore
construct:use
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:higher-order-functions
technique:recursion
uses:List+
ErikSchierboom commented 1 year ago

Exercise: etl

Code

etl.transform : Map Nat [Char] -> Map Char Nat
etl.transform lettersByScore = --todo "implement transform"
   Each.toList do
        k = each (Map.keys lettersByScore) 
        b = Map.get k lettersByScore 
                |> getOrElse [] 
                |> List.map toLowercase
                |> each 
        (b, k)
    |> Map.fromList

Tags:

construct:char
construct:comment
construct:do
construct:each
construct:function
construct:invocation
construct:lambda
construct:list
construct:map
construct:parameter
construct:pipeline
construct:tuple
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:higher-order-functions
uses:List
uses:Map
uses:Tuple
ErikSchierboom commented 12 months ago

This is an automated comment

Hello :wave: Next week we're going to start using the tagging work people are doing on these. If you've already completed the work, thank you! If you've not, but intend to this week, that's great! If you're not going to get round to doing it, and you've not yet posted a comment letting us know, could you please do so, so that we can find other people to do it. Thanks!