concrete NumeralKor of Numeral = CatKor [Numeral,Digits,Decimal] **
  open Prelude, ResKor in {

lincat
  Digit = LinDigit ;
  Sub10,
  Sub100,
  Sub1000,
  Sub1000000,
  Sub1000000000,
  Sub1000000000000 = ResKor.Numeral ;

lin
  -- : Sub1000000 -> Numeral ;              -- 123456 [coercion to top category]
  num x = x ;

  -- : Digit ;
  n2 = mkNum4 "이" "둘" "두" "스물" ** {isTwo=True} ;
  n3 = mkNum4 "삼" "셋" "세" "서른" ;
  n4 = mkNum4 "사" "넷" "네" "마흔" ;
  n5 = mkNum4 "오" "다섯" "다섯" "쉰" ;
  n6 = mkNum2 "육" "여섯" ;
  n7 = mkNum2 "칠" "일곱" ;
  n8 = mkNum2 "팔" "여덟" ;
  n9 = mkNum2 "구" "아홉" ;

  -- : Sub10 ;                              -- 1
  pot01 = mkNum5 "일" "하나" "한" "첫" "열" ;

  -- : Digit -> Sub10 ;                     -- d * 1
  pot0 x = x ;

  -- : Sub100 ;                             -- 10
  pot110 = mkNum2 "십" "열" ;

  -- : Sub100 ;                             -- 11
  pot111 = mkNum4 "십일" "열하나" "열한" "십첫" ; -- TODO check

  -- : Digit -> Sub100 ;                    -- 10 + d
  pot1to19 d = let newS = xPlus "십" "열" d.s in d ** {
    s = newS ;
    n = numNumber ;
    ord = newS ! NK ! Attrib ++ "번째" ;
    } ;

  -- : Sub10 -> Sub100 ;                    -- coercion of 1..9
  pot0as1 x = x ;

  -- : Digit -> Sub100 ;                    -- d * 10
  pot1 d = let sk = potTimes "십" "열" d in sk ** {
    s = table {
          SK => sk.s ! SK ;
          NK => case d.isTwo of {
                        True  => table {Attrib => "스무" ; Indep => "스물"} ;
                        False => table {_ => d.ten}
                      }
        }
    } ;

  -- : Digit -> Sub10 -> Sub100 ;           -- d * 10 + n
  pot1plus d n =
    let dx10 = pot1 d ;
        tenSK = glue (dx10.s ! SK ! Indep) "십" ;
        tenNK = d.ten ;
        newS = xPlus tenSK tenNK n.s
     in dx10 ** {
          s = newS ;
          ord = newS ! NK ! Attrib ++ "번째" ; -- TODO check
          } ;

  -- : Sub100 -> Sub1000 ;                  -- coercion of 1..99
  pot1as2 x = x ;

  -- : Sub10 -> Sub1000 ;                   -- m * 100
  pot2 = potTimes "백" "백" ;

  -- : Sub10 -> Sub100 -> Sub1000 ;         -- m * 100 + n
  pot2plus m n = TODO ;

  -- : Sub1000 -> Sub1000000 ;              -- coercion of 1..999
  pot2as3 x = x ;

  -- : Sub1000 -> Sub1000000 ;              -- m * 1000
  pot3 m = TODO ;

  -- : Sub1000 -> Sub1000 -> Sub1000000 ;   -- m * 1000 + n
  pot3plus m n = TODO ;

  pot3as4 x = x ;
  pot4as5 x = x ;

oper
  LinDigit : Type = ResKor.Numeral ** {isTwo : Bool ; ten : Str} ;

  mkNum2 : (sk, nk : Str) -> LinDigit =
    \sk,nk -> mkNum5 sk nk nk nk (sk+"십") ; -- Digits >5: no NK form for d*10

  mkNum4 : (x1,_,_,x4 : Str) -> LinDigit =
    \sk,nk,ord,ten -> mkNum5 sk nk ord ord ten ; -- Digits >4: NK attrib==indep

  mkNum5 : (x1,_,_,_,x5 : Str) -> LinDigit = \sk,nk,nkAttr,ord,ten -> {
    s = table {
          SK => \\_ => sk ;
          NK => table {Indep => nk ; _ => nkAttr }
          } ;
    n = numNumber ;
    numtype = IsNum ;
    isTwo = False ;
    ten = ten ;
    ord = ord ++ "번째" ;
  } ;

  NumForm : Type = NumOrigin => DForm => Str ;

  xTimes : (tenSK, tenNK : Str) -> NumForm -> NumForm = \sk,nk,tbl ->
    table {SK => \\df => glue (tbl ! SK ! df)    sk ;
           NK => \\df => glue (tbl ! NK ! Indep) nk } ;
  xPlus : (tenSK, tenNK : Str) -> NumForm -> NumForm = \sk,nk,tbl ->
    table {SK => \\df => glue sk (tbl ! SK ! df) ;
           NK => \\df => glue nk (tbl ! NK ! df) } ;

  potTimes : (sk,nk : Str) -> ResKor.Numeral -> ResKor.Numeral = \sk,nk,num ->
    let newS = xTimes sk nk num.s in num ** {
      s = newS ;
      n = numNumber ;
      ord = newS ! NK ! Attrib ++ "번째" ; -- TODO check
    } ;

  TODO : ResKor.Numeral = mkNum2 "TODO" "TODO" ;


-- numerals as sequences of digits

lincat
  Dig = TDigit ;

lin
  -- : Dig -> Digits ;       -- 8
  IDig d = d ;

  -- : Dig -> Digits -> Digits ; -- 876
  IIDig d i = {
    s = \\o => d.s ! NCard ++ BIND ++ i.s ! o ;
    n = numNumber
  } ;

  D_0 = mkDig "0" ;
  D_1 = mk3Dig "1" "1번째" ResKor.Sg ;
  D_2 = mkDig "2" ;
  D_3 = mkDig "3" ;
  D_4 = mkDig "4" ;
  D_5 = mkDig "5" ;
  D_6 = mkDig "6" ;
  D_7 = mkDig "7" ;
  D_8 = mkDig "8" ;
  D_9 = mkDig "9" ;
  
  PosDecimal d = d ** {hasDot=False} ;
  NegDecimal d = {s=\\o=>"-" ++ BIND ++ d.s ! o; hasDot=False; n = Pl} ;
  IFrac d i = {
    s=\\o=>d.s ! NCard ++
           if_then_Str d.hasDot BIND (BIND++"."++BIND) ++
           i.s ! o ;
    hasDot=True;
    n = Pl
    } ;

oper
  mk2Dig : Str -> Str -> TDigit = \c,o -> mk3Dig c o numNumber ;
  mkDig : Str -> TDigit = \c -> mk2Dig c (c + "번째") ;

  mk3Dig : Str -> Str -> ResKor.Number -> TDigit = \c,o,n -> {
    s = table {NCard => c ; NOrd  => o} ;
    n = n
    } ;

  TDigit = {
    n : ResKor.Number ;
    s : CardOrd => Str
  } ;

  numNumber = Sg ; -- No need for 들 with numerals
}
