Task

Take a   Natural Number   in a given base and return the sum of its digits:

   110         sums to   1
   123410   sums to   10
   fe16       sums to   29
   f0e16     sums to   29


go =>
 
  println(1=sum_digits(1)),
  println(1234=sum_digits(1234)),
 
  println('"1234"'=sum_digits("1234")),
  println(1234=sum_digits(1234)),
 
  println('"fe(16)"'=sum_digits("fe", 16)), % -> 29
  println('"f0e(16)"'=sum_digits("f0e", 16)), % -> 29
  println('"FOE(16)"'=sum_digits("F0E", 16)), % -> 29
  println('123(16)'=sum_digits(123, 16)), % -> 6
  println('"123"(16)'=sum_digits("123", 16)), % -> 6
 
  println('"1110010101"(2)'=sum_digits("1110010101", 2)),
 
  println('"picat"(36)'=sum_digits("picat", 36)),
 
  Alpha = "0123456789abcdefghijklmnopqrstuvwxyz",
  Rand = [Alpha[1+random2() mod Alpha.length] : _ in 1..40],
  println(rand=Rand),
  println(rand_sum_digits=sum_digits(Rand, 36)),
 
  println("\nTesting exceptions"),
  catch(println(sum_digits(Rand, 10)), E, println(exception=E)), % bad_base
  catch(println(sum_digits("picat_is_fun!", 36)), E2, println(exeption=E2)), % bad_digit
  catch(println(sum_digits("11100101", 1)),E3,println(exception=E3)), % bad base
  catch(println(sum_digits("hi", 100)), E4, println(exception=E4)), % bad base
 
  % Output base
  println("\nOutput base"),
  println('"fe(16,10)"'=sum_digits("fe", 16,10)), % -> 29
  println('"fe(16,16)"'=sum_digits("fe", 16,16)), % -> 1d
  println('"f0e(16,16)"'=sum_digits("f0e", 16,16)), % -> 1d
  println('"1110010101"(2,2)'=sum_digits("1110010101", 2,2)), % -> 110
  println('"rosetta(36,36)"'=sum_digits("rosetta", 36,36)), % 4h
  nl.
 
% base 10
sum_digits(N) = sum([D.to_integer() : D in N.to_string()]), integer(N) => true.
sum_digits(N) = sum([D.to_integer() : D in N]), string(N) => true.
 
% base Base
sum_digits(N,Base) = sum_digits(N.to_string(), Base), integer(N) => true.
sum_digits(N,Base) = sum_digits(N,Base,10), string(N) => true.
sum_digits(N,Base,OutputBase) = Sum, string(N) =>
  N := to_lowercase(N),
  Alpha = "0123456789abcdefghijklmnopqrstuvwxyz",
  Map = new_map([A=I : {A,I} in zip(Alpha,0..length(Alpha)-1)]),
  M = [Map.get(I,-1) : I in N],
  if max(M) >= Base ; Base < 2; Base > Alpha.length then
    throw $bad_base('N'=N,base=Base)
  elseif min(M) == -1 then
    throw $bad_digits('N'=N,bad=[D : D in N, not Map.has_key(D) ])
  else
    if OutputBase != 10 then
      Sum = dec_to_base(sum(M),OutputBase)
    else 
      Sum = sum(M)
    end
  end.
 
dec_to_base(N, Base) = [Alpha[D+1] : D in reverse(Res)] =>
  Alpha = "0123456789abcdefghijklmnopqrstuvwxyz",
  Res = [],
  while (N > 0) 
    R := N mod Base,
    N := N div Base,
    Res := Res ++ [R]
  end.
 
base_to_dec(N, Base) = base_to_dec(N.to_string(), Base), integer(N) => true.
base_to_dec(N, Base) = Res =>
  println($base_to_dec(N, Base)),
  Alpha = "0123456789abcdefghijklmnopqrstuvwxyz",
  Map = new_map([A=I : {A,I} in zip(Alpha,0..length(Alpha)-1)]),
  Len = N.length,
  Res = sum([Map.get(D)*Base**(Len-I) : {D,I} in zip(N,1..N.length)]).