最近,我一直在Haskell中使用精练进行细化类型,并且遇到了一个主要的可用性问题。我不知道如何在编译时细化整个值列表。
例如,我可以写:
{-# 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魔法可以让我这么做?
如果有人有建议的话,也可以接受更好的轻量级精化类型库的建议。
发布于 2020-03-11 01:56:05
sequenceQTExpList :: [Q (TExp a)] -> Q (TExp [a])
sequenceQTExpList [] = [|| [] ||]
sequenceQTExpList (x:xs) = [|| $$(x) : $$(sequenceQTExpList xs) ||]然后用它作为
$$(sequenceQTExpList $ map refineTH [1..3])你说得对,这感觉就像一次穿越。但是,类型有点不一样,额外的Q在周围浮动。我没有看到任何可以让你有效地组合这些层的随意的东西。
不幸的是,这里使用的很多机制都是TH语法,而不是函数。只是没有一种明显的方法可以同时完成提升和剪接作为函数,所以您只能为每种容器类型编写定制助手,而不是使用Traversable。这是个有趣的问题。如果有一个干净的解决方案,它将很有可能使它成为未来版本的模板Haskell,如果它是向维护人员提出的。但我现在看不出来。
发布于 2020-03-11 01:37:29
这是可行的(但由于阶段限制,它必须位于与您使用的文件不同的文件中):
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的一些安全性(尽管我认为这种情况是安全的)。理想情况下,我更喜欢一种不需要这样做的方法,但我想不出其中一种。
https://stackoverflow.com/questions/60627472
复制相似问题