如何将 [TExp a] 转换为 TExp [a],或者以其他方式以编程方式将 refineTH 应用于多个值?
How can I turn a [TExp a] into a TExp [a], or otherwise apply refineTH to multiple values programatically?
我最近在 Haskell 中使用 refined 进行优化类型,遇到了一个主要的可用性问题。我不知道如何在编译时优化整个值列表。
例如我可以写:
{-# LANGUAGE TemplateHaskell #-}
import Refined
oneToThree :: [Refined Positive Int]
oneToThree = [$$(refineTH 1), $$(refineTH 2), $$(refineTH 3)]
但是我不能这样做排除了使用范围语法的能力,因为 Refined
没有(出于充分的理由)有 Enum
.
的实例
我希望能够做类似
的事情
oneToThree :: [Refined Positive Int]
oneToThree = $$(traverse refineTH [1..3])
但我无法编译它,因为我无法将 [TExp (Refined Positive Int)]
提升到 TExp [Refined Positive Int]
。
是否有我缺少的模板 haskell 魔法可以让我这样做?
如果有人有建议,我们也会接受关于更好的轻量级优化类型库的建议。
这有效(但由于阶段限制,它需要位于与您使用它不同的文件中):
import Language.Haskell.TH.Syntax (Exp(ListE), TExp(TExp))
makeTypedTHList :: [TExp a] -> TExp [a]
makeTypedTHList xs = TExp $ ListE [x | TExp x <- xs]
然后您可以像这样使用它:
{-# LANGUAGE TemplateHaskell #-}
import Refined
import AboveCodeInSeparateModuleBecauseOfStageRestriction (makeTypedTHList)
oneToThree :: [Refined Positive Int]
oneToThree = $$(makeTypedTHList <$> traverse refineTH [1..3])
但是,自己调用 TExp
构造函数会破坏类型化模板 Haskell 的某些安全性(尽管我认为这种特殊情况是安全的)。理想情况下,我更喜欢不需要这样做的方法,但我想不出一个。
sequenceQTExpList :: [Q (TExp a)] -> Q (TExp [a])
sequenceQTExpList [] = [|| [] ||]
sequenceQTExpList (x:xs) = [|| $$(x) : $$(sequenceQTExpList xs) ||]
然后用作
$$(sequenceQTExpList $ map refineTH [1..3])
你说得对,感觉像是穿越。但是,该类型有点偏离,额外的 Q
s 浮动。我没有立即看到任何可以让您有用地组合这些层的东西。
不幸的是,那里使用的很多机制都是 TH 语法而不是函数。只是没有一种明显的方法可以将提升和拼接作为函数进行,因此您不得不为每种容器类型编写定制的帮助程序,而不是开始使用 Traversable
。这是一个有趣的问题。如果有一个干净的解决方案,如果它被提交给维护者,它很有可能成为模板 Haskell 的未来版本。但是我现在看不到它。
我最近在 Haskell 中使用 refined 进行优化类型,遇到了一个主要的可用性问题。我不知道如何在编译时优化整个值列表。
例如我可以写:
{-# LANGUAGE TemplateHaskell #-}
import Refined
oneToThree :: [Refined Positive Int]
oneToThree = [$$(refineTH 1), $$(refineTH 2), $$(refineTH 3)]
但是我不能这样做排除了使用范围语法的能力,因为 Refined
没有(出于充分的理由)有 Enum
.
我希望能够做类似
的事情oneToThree :: [Refined Positive Int]
oneToThree = $$(traverse refineTH [1..3])
但我无法编译它,因为我无法将 [TExp (Refined Positive Int)]
提升到 TExp [Refined Positive Int]
。
是否有我缺少的模板 haskell 魔法可以让我这样做?
如果有人有建议,我们也会接受关于更好的轻量级优化类型库的建议。
这有效(但由于阶段限制,它需要位于与您使用它不同的文件中):
import Language.Haskell.TH.Syntax (Exp(ListE), TExp(TExp))
makeTypedTHList :: [TExp a] -> TExp [a]
makeTypedTHList xs = TExp $ ListE [x | TExp x <- xs]
然后您可以像这样使用它:
{-# LANGUAGE TemplateHaskell #-}
import Refined
import AboveCodeInSeparateModuleBecauseOfStageRestriction (makeTypedTHList)
oneToThree :: [Refined Positive Int]
oneToThree = $$(makeTypedTHList <$> traverse refineTH [1..3])
但是,自己调用 TExp
构造函数会破坏类型化模板 Haskell 的某些安全性(尽管我认为这种特殊情况是安全的)。理想情况下,我更喜欢不需要这样做的方法,但我想不出一个。
sequenceQTExpList :: [Q (TExp a)] -> Q (TExp [a])
sequenceQTExpList [] = [|| [] ||]
sequenceQTExpList (x:xs) = [|| $$(x) : $$(sequenceQTExpList xs) ||]
然后用作
$$(sequenceQTExpList $ map refineTH [1..3])
你说得对,感觉像是穿越。但是,该类型有点偏离,额外的 Q
s 浮动。我没有立即看到任何可以让您有用地组合这些层的东西。
不幸的是,那里使用的很多机制都是 TH 语法而不是函数。只是没有一种明显的方法可以将提升和拼接作为函数进行,因此您不得不为每种容器类型编写定制的帮助程序,而不是开始使用 Traversable
。这是一个有趣的问题。如果有一个干净的解决方案,如果它被提交给维护者,它很有可能成为模板 Haskell 的未来版本。但是我现在看不到它。