如何将[TExp a]转换为TExp [a],或者以编程方式将fineTH应用于多个值?

问题描述 投票:2回答:2

我最近在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魔术能让我做到这一点?

如果有人提出建议,也将接受关于更好的轻量级精炼类型库的建议。

haskell template-haskell refinement-type
2个回答
0
投票

此方法有效(由于阶段限制,它必须与您使用的文件位于不同的文件中:]

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的某些安全性(尽管我认为这种特殊情况是安全的)。理想情况下,我更喜欢一种不需要这样做的方法,但我想不到一个。


0
投票
sequenceQTExpList :: [Q (TExp a)] -> Q (TExp [a])
sequenceQTExpList [] = [|| [] ||]
sequenceQTExpList (x:xs) = [|| $$(x) : $$(sequenceQTExpList xs) ||]

然后将其用作

$$(sequenceQTExpList $ map refineTH [1..3])

您是对的,感觉就像是遍历。但是,类型略有不同,多余的Q随处可见。我看不到任何可以使您有效地合并这些图层的东西。

[不幸的是,这里使用的许多机制都是TH语法而不是函数。只是没有一个明显的方法可以同时完成作为函数的提升和拼接,因此您不得不为每种容器类型编写定制的帮助程序,而不必使用Traversable。这是一个有趣的问题。如果有一个干净的解决方案,那么如果将其提交给维护人员,则很有可能将其纳入模板Haskell的未来版本中。但是我现在看不到。

© www.soinside.com 2019 - 2024. All rights reserved.