exercism / nim

Exercism exercises in Nim.
https://exercism.org/tracks/nim
MIT License
56 stars 25 forks source link

Building a training set of tags for nim #548

Closed iHiD closed 10 months ago

iHiD commented 11 months 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

iHiD commented 11 months ago

Exercise: two-fer

Code

import strformat
proc twoFer(name: string = "you") : string = fmt"One for {name}, one for me."

Tags:

construct:string-interpolation
construct:assignment
construct:default-parameter-value
construct:import
construct:invocation
construct:parameter
construct:procedure
construct:proc
construct:return
construct:string
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:functional
technique:string-interpolation
iHiD commented 11 months ago

Exercise: reverse-string

Code

import strutils

proc reverseString*(s: var string) =
    for i in 0 .. s.high div 2:
        swap(s[i],  s[s.high - i])

Tags:

construct:assignment
construct:for-loop
construct:function
construct:import
construct:indexing
construct:int
construct:integral-number
construct:invocation
construct:loop
construct:number
construct:parameter
construct:procedure
construct:subtract
construct:swap
construct:varargs
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:looping
technique:mutability
technique:recursion
uses:strutils.swap
iHiD commented 11 months ago

Exercise: bob

Code

import nre 
import strutils

proc isNothing(input: string): bool =
  strip(input) == ""

proc isYell(input: string): bool =
  input == toUpper(input) and contains(input, re"""[A-Z]""")

proc isQuestion(input: string): bool =
  endsWith(strip(input), "?")

proc hey*(input: string): string =
  if isNothing(input):
    "Fine. Be that way!"
  elif isYell(input):
    "Whoa, chill out!"
  elif isQuestion(input):
    "Sure."
  else:
    "Whatever."

Tags:

construct:boolean
construct:and
construct:elif
construct:else
construct:if
construct:import
construct:invocation
construct:lambda
construct:logical-and
construct:procedure
construct:string
construct:template
construct:underscore
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:higher-order-functions
iHiD commented 11 months ago

Exercise: acronym

Code

import strutils

proc abbreviate*(sentence: string): string =
  for word in split(sentence, WhiteSpace + {',', '-'}):
    if len(word) > 0:
      var first = ord(word[0])
      if first >= 97 and first <= 122:
        first -= 32
      if first >= 65 and first <= 90:
        result.add(chr(first))

Tags:

construct:add
construct:and
construct:assignment
construct:char
construct:for-loop
construct:if
construct:implicit-conversion
construct:indexing
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:len
construct:logical-and
construct:method
construct:number
construct:parameter
construct:proc
construct:string
construct:subtract
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:higher-order-functions
technique:looping
iHiD commented 11 months ago

Exercise: matching-brackets

Code

import tables

const Pairs = {')': '(', '}': '{', ']': '['}.toTable

proc isPaired*(str: string): bool =  
  var stack: seq[char] = @[]
  for c in str:
    if c in {'(', '{', '['}:
      stack.add(c)
    elif c in {')', '}', ']'}:
      if len(stack) > 0 and stack[^1] == Pairs[c]:
        setLen(stack, high(stack))
      else:
        return false
  len(stack) == 0

Tags:

construct:and
construct:assignment
construct:boolean
construct:char
construct:const
construct:dictionary
construct:elif
construct:for-loop
construct:if
construct:implicit-conversion
construct:indexing
construct:invocation
construct:len
construct:logical-and
construct:method
construct:number
construct:parameter
construct:proc
construct:return
construct:set
construct:string
construct:table
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:looping
uses:tables.Set
uses:tables.Table
iHiD commented 11 months ago

Exercise: triangle

Code

type
  TriangleKind* = enum
    tkEquilateral,
    tkIsosceles,
    tkScalene,

proc isValid(a: float64, b: float64, c: float64): bool =
  let longestSide = a.max(b).max(c)
  let sumOfAll = a + b + c
  longestSide < sumOfAll - longestSide

proc kind*(a: float64, b: float64, c: float64): TriangleKind =
  if not isValid(a, b, c):
    raise newException(ValueError, "Invalid triangle")

  if a == b and a == c:
    tkEquilateral
  elif a == b or a == c or b == c:
    tkIsosceles
  else:
    tkScalene

Tags:

construct:add
construct:and
construct:boolean
construct:custom-type
construct:elif
construct:enum
construct:float
construct:floating-point-number
construct:if
construct:invocation
construct:lambda
construct:logical-and
construct:logical-or
construct:method
construct:named-argument
construct:parameter
construct:subtract
construct:throw
construct:visibility-modifiers
paradigm:functional
paradigm:object-oriented
technique:boolean-logic
technique:exceptions
technique:higher-order-functions
iHiD commented 11 months ago

Exercise: nucleotide-count

Code

import sequtils, tables

proc count*(c: char, input: string): int =
  input.filterIt(it == c).len

proc countDna*(input: string): Table[char, int] =
  "ACTG"
    .mapIt((it, count(it, input)))
    .filterIt(it[1] > 0)
    .toTable

Tags:

construct:assignment
construct:char
construct:comment
construct:explicit-conversion
construct:extension-method
construct:header
construct:import
construct:indexing
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:method
construct:number
construct:parameter
construct:proc
construct:string
construct:table
construct:tuple
construct:underscore
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
technique:type-conversion
uses:Table
uses:sequtils.filterIt
iHiD commented 11 months ago

Exercise: react

Code

import sequtils
import tables

type
  CallbackID = int
  Callback = proc(val: int)
  CellFormula = proc(vals: seq[int]): int
  Cell* = ref object
    value: int
    dependents*: seq[Cell]
    callbacks: Table[CallbackID, Callback]
    inputCells: seq[Cell]
    formula: CellFormula

# not used in my implementation
type Reactor = ref object

proc newReactor*(): Reactor = Reactor()

proc createInput*(this: Reactor, value: int): Cell =
  Cell(value: value, dependents: newSeq[Cell]())

proc applyFormula(this: Cell): tuple[oldValue: int, newValue: int] =
  var inputs = this.inputCells.map(proc(input: Cell): int = input.value)
  var oldValue = this.value
  var newValue = this.formula(inputs)
  this.value = newValue
  (oldValue: oldValue, newValue: newValue)

proc updateValue(this: Cell, callbacksTriggered: var seq[CallbackID]) =
  var (oldValue, newValue) = this.applyFormula()

  if oldValue != newValue:
    for id, callback in pairs(this.callbacks):
      if not callbacksTriggered.contains(id):
        callbacksTriggered.add(id)
        callback(newValue)

  for dependent in this.dependents:
    dependent.updateValue(callbacksTriggered)

proc value*(this: Cell): int =
  this.value

proc `value=`*(this: Cell, value: int) =
  this.value = value
  var callbacksTriggered = newSeq[CallbackID]()
  for dependent in this.dependents:
    dependent.updateValue(callbacksTriggered)

proc createCompute*(this: Reactor, cells: seq[Cell], formula: CellFormula): Cell =
  var formulaCell = Cell(inputCells: cells, formula: formula, dependents:
  newSeq[Cell](), callbacks: initTable[CallbackID, Callback]())

  for ancestor in cells:
    ancestor.dependents.add(formulaCell)

  discard formulaCell.applyFormula()
  formulaCell

var nextCallbackID = -1

proc newCallbackID(): CallbackID =
  inc(nextCallbackID)
  nextCallbackID

proc addCallback*(this: Cell, callback: Callback): CallbackID =
  var id = newCallbackID()
  this.callbacks[id] = callback
  return id

proc removeCallback*(this: Cell, callbackId: CallbackID) =
  this.callbacks.del(callbackId)

Tags:

construct:assignment
construct:biggest-int
construct:comment
construct:constructor
construct:for-loop
construct:if
construct:import
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:method
construct:named-argument
construct:nested-type
construct:parameter
construct:proc
construct:proc-type
construct:read-only
construct:return
construct:table
construct:tuple
construct:type
construct:underscored-id
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
technique:looping
uses:Table
iHiD commented 11 months ago

Exercise: grade-school

Code

import algorithm

type
  Student = tuple
    name : string
    grade : int

  School* = object
    students* : seq[Student]

proc grade*(sch:School, n:int):seq[string] =
  for i in sch.students:
    if i.grade==n:
      result.add(i.name)
  result.sort((proc (x, y:string): int = cmp(x,y)))

proc roster*(sch:School):seq[string] =
  for i in 1..9:
    result.add(sch.grade(i))

Tags:

construct:add
construct:assignment
construct:for-loop
construct:function
construct:if
construct:import
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:method
construct:number
construct:object
construct:overloading
construct:parameter
construct:proc
construct:procedure
construct:result
construct:seq
construct:sort
construct:string
construct:tuple
construct:type
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
technique:looping
uses:algorithm.sort
iHiD commented 11 months ago

Exercise: collatz-conjecture

Code

import os
import rdstdin, strutils

var number = parseInt(readLineFromStdin ": ")

echo number

while number != 1:
  if number mod 2 == 0:
    number = number div 2
    echo number
  else:
    number = 3 * number + 1
    echo number

echo "done"

Tags:

construct:add
construct:assignment
construct:div
construct:echo
construct:if
construct:import
construct:int
construct:integral-number
construct:invocation
construct:mod
construct:multiply
construct:number
construct:parameter
construct:readLineFromStdin
construct:string
construct:variable
construct:visibility-modifiers
construct:while-loop
paradigm:imperative
paradigm:object-oriented
technique:looping
iHiD commented 11 months ago

Exercise: etl

Code

import tables, strutils

proc transform*(input: Table[int, seq[char]]): Table[char, int] =
  for score, letters in input:
    for letter in letters:
      result[letter.toLowerAscii] = score

Tags:

construct:assignment
construct:for-loop
construct:import
construct:indexed-access
construct:invocation
construct:method
construct:named-argument
construct:overloading
construct:parameter
construct:proc
construct:procedure
construct:string
construct:table
construct:underscored-identifier
construct:visibility-modifiers
paradigm:imperative
paradigm:reflective
technique:looping
iHiD commented 11 months ago

Exercise: high-scores

Code

from algorithm import sort, SortOrder

func latest*(scores: seq[int]): int =
  scores[^1]

func personalBest*(scores: seq[int]): int =
  for n in scores:
    if result < n: result = n

func personalTopThree*(scores: seq[int]): seq[int] =
  var sorted = scores
  sorted.sort(order = Descending)
  result = if scores.len < 4: sorted
           else: sorted[0..2]

Tags:

construct:assignment
construct:for-loop
construct:if
construct:if-expression
construct:indexing
construct:int
construct:integral-number
construct:invocation
construct:lowercase-letter
construct:named-argument
construct:number
construct:parameter
construct:range
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:looping
uses:SortOrder
iHiD commented 11 months ago

Exercise: prime-factors

Code

func primeFactors*(n: int64): seq[int] =
  var
    m = n
    i = 2
  while m != 1:
    if m mod i == 0:
      result.add i
      m = m div i
    else:
      i += 1

Tags:

construct:assignment
construct:if
construct:int64
construct:method
construct:parameter
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
iHiD commented 11 months ago

Exercise: clock

Code

import strformat

const day = 24 * 60

proc create*(hm: (int, int)): int =
  let (hours, minutes) = hm
  ((minutes + hours * 60) mod day + day) mod day

proc toStr*(clock: int): string =
  let (hours, minutes) = (clock div 60, clock mod 60)
  &"{hours:02}:{minutes:02}"

proc add*(hm: (int, int), minutes: int): int =
  create((hm[0], hm[1] + minutes))

proc subtract*(hm: (int, int), minutes: int): int =
  add(hm, -minutes)

Tags:

construct:add
construct:assignment
construct:bitwise-and
construct:const
construct:divide
construct:import
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:number
construct:parameter
construct:pattern-matching
construct:proc
construct:string
construct:tuple
construct:underscore
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:bit-manipulation
technique:bit-shifting
technique:higher-order-functions
uses:strformat
iHiD commented 11 months ago

Exercise: diamond

Code

import algorithm, sequtils, strformat, strutils

type
  LetterOffset = tuple
    letter: char
    offset: int

proc offsets(letters: seq[char]): seq[LetterOffset] =
  for i, c in letters:
    result.add((c, i))

  result.add(result[0..^2].reversed)

proc line(letterOffset: LetterOffset, letterCount: int): string =
  let (letter, offset) = letterOffset

  let outerSpaces = "".alignLeft(letterCount - offset - 1);
  let innerSpaces = "".alignLeft(if offset == 0: 0 else: offset * 2 - 1);

  if letter == 'A':
    &"{outerSpaces}{letter}{outerSpaces}\n"
  else:
    &"{outerSpaces}{letter}{innerSpaces}{letter}{outerSpaces}\n";

proc diamond*(letter: char): string =
  let letters = toSeq('A' .. letter)
  letters.offsets.mapIt(line(it, letters.len)).join()

Tags:

construct:string-interpolation
construct:assignment
construct:char
construct:for-loop
construct:if
construct:implicit-conversion
construct:indexing
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:method
construct:multiply
construct:named-argument
construct:number
construct:parameter
construct:proc
construct:range
construct:string
construct:subtract
construct:ternary
construct:tuple
construct:type
construct:underscore-number
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
technique:looping
uses:tuple
iHiD commented 11 months ago

Exercise: diffie-hellman

Code

import math, random

proc privateKey*(p: int): int = 
  result = rand(p-3) + 2

proc secret*(p, theirPubKey, myPrivKey: int): int =
  ( theirPubKey ^ myPrivKey ) mod p

proc publicKey*(p, g, privKey: int): int = 
  secret(p, g, privKey)

Tags:

construct:add
construct:assignment
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:mod
construct:number
construct:parameter
construct:proc
construct:subtract
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
technique:math
technique:randomness
iHiD commented 11 months ago

Exercise: proverb

Code

import
  strformat

func recite*(words: seq[string]): string =
  if words.len == 0: return
  var
    first, second: string
  for i in 0 .. words.len - 2:
    first = words[i]
    second = words[i + 1]
    result.add &"For want of a {first} the {second} was lost.\n"
  first = words[0]
  result.add &"And all for the want of a {first}."

Tags:

construct:add
construct:assignment
construct:bitwise-and
construct:for-loop
construct:function
construct:if
construct:import
construct:indexing
construct:int
construct:integral-number
construct:method
construct:number
construct:parameter
construct:return
construct:sequence
construct:string
construct:subtract
construct:template-string
construct:variable
construct:visibility-modifiers
paradigm:imperative
paradigm:object-oriented
technique:bit-manipulation
technique:bit-shifting
technique:looping
uses:strformat.BitManipulation
iHiD commented 11 months ago

Exercise: resistor-color-duo

Code


type
    Color* = enum
        Black, Brown, Red, Orange,
        Yellow, Green, Blue, Violet, Grey, White

proc value*(colors: openArray[Color]): int =
    colors[0].ord * 10 + colors[1].ord

Tags:

construct:add
construct:array
construct:enum
construct:implicit-conversion
construct:indexing
construct:int
construct:integral-number
construct:multiply
construct:number
construct:open-array
construct:parameter
construct:proc
construct:type-conversion
construct:visibility-modifier
paradigm:functional
paradigm:multiparadigm
paradigm:object-oriented
technique:bit-manipulation
technique:bit-shifting
technique:math
iHiD commented 11 months ago

Exercise: robot-name

Code

import random

type Robot* = object
  name*: string

proc reset*(robot: var Robot)

proc makeRobot*(): Robot =
  var robot = Robot()
  robot.reset()
  robot

proc reset*(robot: var Robot) =
  robot.name = ""
  while robot.name.len < 2:
    robot.name &= chr(rand(25) + ord('A'))
  while robot.name.len < 5:
    robot.name.addInt(rand(9))

Tags:

construct:add
construct:assignment
construct:char
construct:class
construct:implicit-conversion
construct:int
construct:integral-number
construct:invocation
construct:method
construct:number
construct:overloading
construct:parameter
construct:proc
construct:random
construct:string
construct:type
construct:variable
construct:visibility-modifiers
construct:while-loop
paradigm:imperative
paradigm:object-oriented
technique:looping
technique:randomness
uses:random
uses:random.NumberGenerator
iHiD commented 11 months ago

Exercise: scale-generator

Code

import strutils

const sharps = "C C# D D# E F F# G G# A A# B ".repeat(2).splitWhitespace()
const flats = "C Db D Eb E F Gb G Ab A Bb B ".repeat(2).splitWhitespace()
const useFlats = " F Bb Eb Ab Db Gb d g c f bb eb "

proc scale*(tonic: string, intervals = "mmmmmmmmmmmm"): seq[string] =
  let tones = if useFlats.contains(" $1 " % [tonic]): flats else: sharps
  var startTone = tonic
  startTone[0] = startTone[0].toUpperAscii
  result.add(startTone)
  var idx = tones.find(startTone)
  for i in 0..<intervals.high:
    let interval = intervals[i]
    let offset = if interval == 'm': 1 elif interval == 'M': 2 else: 3
    idx += offset
    result.add(tones[idx])

Tags:

construct:assignment
construct:char
construct:const
construct:for-loop
construct:if
construct:implicit-conversion
construct:indexing
construct:int
construct:integral-number
construct:invocation
construct:lambda
construct:let
construct:method
construct:number
construct:optional-parameter
construct:parameter
construct:proc
construct:string
construct:variable
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:higher-order-functions
technique:looping
ynfle commented 10 months ago

I'd like to help if this is still available

iHiD commented 10 months ago

@ynfle It is - thanks!

ErikSchierboom commented 10 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!

ErikSchierboom commented 10 months ago

@ynfle Just double checking: I don't think I've seen any edits, is that correct?

ErikSchierboom commented 10 months ago

Seeing as there are no edits, I'm gonna close this issue. If you do still want to edit, let me know.

ynfle commented 10 months ago

Thanks Erik. I realized that I don't have the bandwidth for this right now and didn't realize that when I expressed interest