在Haskell中执行类型级`符号格式的最简单方法

发布于 2025-02-10 14:09:54 字数 947 浏览 2 评论 0原文

给定两个 s ab,创建另一个符号的最简单方法是等于b,但其前缀<代码> A 剥离,其余的使案件降低并打开?

例如,如何实现此类型的家族,以使routepath“ foo”“ foo_barqux” ==“ bar-qux”(kebab案例是可选的)?

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

ghc.typelits确实提供 unconssymbol 我可以用来从头开始实现这种事情,但是感觉太低了。我想知道是否有一个现有的解决方案(也许是库),可以将其采用以使代码更小,更简单。

对于真实的上下文,请参见 this pr 特别是structor2routepath 代码>键入家庭。

Given two Symbols a and b, what is the simplest way to create another symbol that is equivalent to b but its prefix a stripped and the rest made lower case and slugified?

For example, how to implement this type family such that RoutePath "Foo" "Foo_BarQux" == "bar-qux" (the kebab case is optional)?

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

GHC.TypeLits does provide UnconsSymbol that I can use to implement this sort of thing from scratch, but it feels too low-level. I'm wondering if there is an existing solution (a library perhaps) that I can adopt to keep code in my library smaller and simpler.

For real-word context, see this PR in particular the Constructor2RoutePath type family.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你げ笑在眉眼 2025-02-17 14:09:54

符号软件包

我遇到了符号软件包。它提供了tolist(sym :: symber):: [符号]键入family,它使我能够处理符号作为列表,但是,我了解到它使它使得它使得汇编非常慢。

GHC 9.2的Unconssymbol

它别无选择,只能升级到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

链接到

它不像我在发布此问题时那样复杂。不过,它并不能进行烤肉箱的转换,但我想这并不是太复杂了。

symbols package

I came across the symbols package. It provides a ToList (sym :: Symbol) :: [Symbol] type family which enables me to process the Symbol as a list, however, I learned that it makes the compilation extremely slow. Here's the code for that.

GHC 9.2's UnconsSymbol

That left me with no choice but to upgrade to GHC 9.2. On the plus side, the compilation is as swift as it was before. Here's the implementation in full:

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

Link to the rewrite.

It is not as complex as I had envisioned it when posting this question. It doesn't do the Kebab case conversion though, but I imagine that's not too complicated to achieve.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文