在Haskell中做类型级' Symbol '格式化的最简单方法



给定两个Symbol,ab,创建另一个相当于b的符号的最简单方法是什么,但其前缀a被剥离,其余部分小写并简化?

例如,如何实现RoutePath "Foo" "Foo_BarQux" == "bar-qux"这样的类型族(kebab的情况是可选的)?

type family RoutePath datatype constr where 
RoutePath datatype constr = undefined -- TODO

GHC.TypeLits确实提供了UnconsSymbol,我可以用它从头开始实现这类事情,但感觉太低级了。我想知道是否有一个现有的解决方案(也许是一个库),我可以采用它来保持我的库中的代码更小,更简单。

对于真实的上下文,请参阅此PR,特别是Constructor2RoutePath类型族。

symbolspackage

我遇到了符号包。它提供了一个ToList (sym :: Symbol) :: [Symbol]类型族,使我能够将Symbol作为列表处理,但是,我了解到它使编译非常慢。下面是代码:

GHC 9.2 sUnconsSymbol

这让我别无选择,只能升级到GHC 9.2。好的一面是,编译速度和以前一样快。下面是完整的实现:

import GHC.TypeLits (ConsSymbol, Symbol, UnconsSymbol)
-- | Strip `prefix` from `symbol`. Return `symbol` as-is if the prefix doesn't match.
type family StripPrefix (prefix :: Symbol) (symbol :: Symbol) :: Symbol where
StripPrefix prefix symbol =
FromMaybe
symbol
(StripPrefix' (UnconsSymbol prefix) (UnconsSymbol symbol))
-- | Strip `prefix` from `symbol`. Return Nothing if the prefix doesn't match.
type family StripPrefix' (prefix :: Maybe (Char, Symbol)) (symbol :: Maybe (Char, Symbol)) :: Maybe Symbol where
StripPrefix' 'Nothing 'Nothing = 'Just ""
StripPrefix' 'Nothing ( 'Just '(x, xs)) = 'Just (ConsSymbol x xs)
StripPrefix' _p 'Nothing = 'Nothing
StripPrefix' ( 'Just '(p, ps)) ( 'Just '(p, ss)) = StripPrefix' (UnconsSymbol ps) (UnconsSymbol ss)
StripPrefix' ( 'Just '(p, ps)) ( 'Just '(_, ss)) = 'Nothing
type family ToLower (sym :: Symbol) :: Symbol where
ToLower sym = ToLower' (UnconsSymbol sym)
type family ToLower' (pair :: Maybe (Char, Symbol)) :: Symbol where
ToLower' 'Nothing = ""
ToLower' ( 'Just '(c, cs)) = ConsSymbol (ToLowerC c) (ToLower' (UnconsSymbol cs))
type family ToLowerC (c :: Char) :: Char where
ToLowerC 'A' = 'a'
ToLowerC 'B' = 'b'
ToLowerC 'C' = 'c'
ToLowerC 'D' = 'd'
ToLowerC 'E' = 'e'
ToLowerC 'F' = 'f'
ToLowerC 'G' = 'g'
ToLowerC 'H' = 'h'
ToLowerC 'I' = 'i'
ToLowerC 'J' = 'j'
ToLowerC 'K' = 'k'
ToLowerC 'L' = 'l'
ToLowerC 'M' = 'm'
ToLowerC 'N' = 'n'
ToLowerC 'O' = 'o'
ToLowerC 'P' = 'p'
ToLowerC 'Q' = 'q'
ToLowerC 'R' = 'r'
ToLowerC 'S' = 's'
ToLowerC 'T' = 't'
ToLowerC 'U' = 'u'
ToLowerC 'V' = 'v'
ToLowerC 'W' = 'w'
ToLowerC 'X' = 'x'
ToLowerC 'Y' = 'y'
ToLowerC 'Z' = 'z'
ToLowerC a = a
type family FromMaybe (def :: a) (maybe :: Maybe a) :: a where
FromMaybe def 'Nothing = def
FromMaybe def ( 'Just a) = a

链接到重写。

它并不像我在发布这个问题时想象的那么复杂。虽然它不做Kebab的大小写转换,但我想这并不太复杂,无法实现。