packages feed

singleraeh-0.1.0: src/Singleraeh/Symbol.hs

{-# LANGUAGE UndecidableInstances #-} -- for RevCharsToSymbol'

module Singleraeh.Symbol where

import Singleraeh.List ( SList(..) )
import Singleraeh.Maybe ( SMaybe(..) )
import Singleraeh.Tuple ( STuple2(..) )
import GHC.TypeLits
import Unsafe.Coerce ( unsafeCoerce )

sConsSymbol :: SChar ch -> SSymbol str -> SSymbol (ConsSymbol ch str)
sConsSymbol ch str =
    withSomeSSymbol (fromSChar ch : fromSSymbol str) unsafeCoerce

-- TODO test!!!
sUnconsSymbol
    :: SSymbol str
    -> SMaybe (STuple2 SChar SSymbol) (UnconsSymbol str)
sUnconsSymbol sstr =
    case fromSSymbol sstr of
      []        -> unsafeCoerce SNothing
      ch : str' -> unsafeCoerce $ SJust $ STuple2
        (withSomeSChar ch unsafeCoerce)
        (withSomeSSymbol str' unsafeCoerce)

-- | Re-construct the output from 'UnconsSymbol'.
type family ReconsSymbol msym where
    ReconsSymbol (Just '(ch, sym)) = ConsSymbol ch sym
    ReconsSymbol Nothing           = ""

sReconsSymbol
    :: SMaybe (STuple2 SChar SSymbol) msym
    -> SSymbol (ReconsSymbol msym)
sReconsSymbol = \case
  SJust (STuple2 ch sym) -> sConsSymbol ch sym
  SNothing               -> SSymbol @""

-- TODO we can write this with @Foldl (FlipSym1 ConsSymbolSym) "" chs@, but
-- we need more singletons then. check it out later :)
type RevCharsToSymbol chs = RevCharsToSymbol' "" chs
type family RevCharsToSymbol' sym chs where
    RevCharsToSymbol' sym (ch : chs) = RevCharsToSymbol' (ConsSymbol ch sym) chs
    RevCharsToSymbol' sym '[]        = sym

revCharsToSymbol :: SList SChar chs -> SSymbol (RevCharsToSymbol chs)
revCharsToSymbol = revCharsToSymbol' (SSymbol @"")

revCharsToSymbol'
    :: SSymbol str
    -> SList SChar chs -> SSymbol (RevCharsToSymbol' str chs)
revCharsToSymbol' sacc = \case
  SCons sch sstr -> revCharsToSymbol' (sConsSymbol sch sacc) sstr
  SNil           -> sacc