Haskell中的泛型类型转换

时间:2011-04-30 08:34:52

标签: generics haskell types arrows algebraic-data-types

我正在尝试编写一个带有常规函数的arrow转换器,并将它们转换为抽象值的计算。如果我们有一个“来源”箭头,

f :: Int -> Int
f x = x + 1

然后目标是让 f 在提升的[sic?]抽象值类型上工作,在这个例子中

f' :: AV Int -> AV Int
f' (Const x) = Const (f x)
-- pass along errors, since AV computation isn't always defined
-- or computable in the case of errors
f' (Error s) = Error s
-- avRep = "abstract representation". Think of symbolic math manipulation or ASTs.
f' (Abstract avRep) = AVRepPlus avRep (AVRepConst 1)

但是,为了成功实现此箭头,需要提升几种类型,以便在任意深度上具有具有一些具体和一些抽象值的异构数据结构。我最终做的是为常规的haskell构造函数添加特殊类型,例如如果

g = uncurry (+) -- i.e. g (x, y) = x + y

然后我为(,),元组构造函数

添加一个抽象表示
AVTuple :: AV a -> AV b -> AV (a, b)

并且 g 的代码被解除为[展开一点],

g' (AVTuple (AVConst a) (AVConst b)) = (AVConst (g (a, b)))
g' (AVTuple (AVError e) _) = (AVError e)
-- symmetric case here, i.e. AVTuple _ (AVError e)
g' (AVTuple a@(AVTuple _ _) b) = -- recursive code here

AVEither也需要做同样的事情。这最终将成为很多案例。这有什么好办法吗?

我是Haskell的新手,所以请给我参考或半详细解释;可能最接近我读过的是SYBR纸(废弃样板转速)第1-3节。

非常感谢你!

2 个答案:

答案 0 :(得分:1)

让我看看我是否理解你在这之后所做的事情。您有一个类型AV a,它描述了一个产生a类型的计算,其中该计算的结构可以以允许检查的方式保存。您想要一种方法将任意函数提升到AV上的操作,保留结构,而不必为每个操作创建特殊情况。

通常,要将功能提升到某个结构,可以使用FunctorApplicative。但是,这样做的直接方法包括转换结构并直接应用提升函数,而不是将函数应用程序保留为结构的一部分。

你想要什么更尴尬,这就是原因:

假设我们有一些我们想要解除的函数,以及两个适当类型的抽象值来应用它:

x :: AV A
x = ...

y :: AV B
y = ...

f :: A -> B -> C
f = ...

假设有一个函数liftAV2可以满足您的需求。我们希望lift2 f的类型为AV A -> AV B -> AV C,就像liftA的{​​{1}}一样。

稍后,我们希望通过恢复Applicativelift2 ff的值来检查使用x生成的计算。让我们说现在我们只想提取第一个参数。假设存在执行此操作的函数y,以便extractArg1 = extractArg1 (liftAV2 f x y)x的类型是什么?在 context 中,我们知道它应该具有类型extractArg1。但它总体上会有什么类型?像AV C -> AV A这样的东西?这是错误的,因为结果不只是任何类型AV c -> AV a,它是用于构造a值的任何类型。假设我们运行的值是使用AV c的结果构造的,我们知道问题类型存在,但我们无法一般地找到它。

这是我们进入适当的土地,存在类型。老实说使用它们,不仅仅是通常情况下误用类型类。

你可以通过一些努力完成你所追求的目标,但这已经进入了相当先进的领域。您可能希望将 GADTs 用于初学者,不过我认为您可能已经这样做了。对于存在类型,它也往往非常笨拙,因为你只能在有限的语境中知道它们是什么。

在您的特定情况下,给liftAV2 f 两个类型参数可能更容易:一个表示计算的最终类型,一个表示计算结构,例如:

AV

然后,为了检查计算,您可以查看第一种类型以了解您拥有的内容;为了构建计算,您可以查看第二个以确保类型匹配。评估函数将具有类似data f :$ x = ... data AV structure result where ... AVApply :: AV f (a -> b) -> AV x a -> AV (f :$ x) b 的类型,从而丢弃结构。你也可以使用结构类型“解包”计算,抛弃结果类型,如果你需要拆开结构,比如说,打印它。

答案 1 :(得分:0)

我喜欢考虑这个问题的方式,当我想谈论一些“额外的数据”时,我会使用Functor实例(取决于“额外的一点”是什么,我可能在实际上是在谈论ApplicativeMonad)。

另一方面,我使用Arrow实例来讨论“功能少一点”:箭头让你可以用与函数相同的方式定义可以组合在一起的东西,但是你可以添加额外的禁止某些结构的结构或限制(例如没有ArrowChoiceArrowLoop的箭头)。

您希望完成的内容并不完全清楚,但听起来您实际上是在AV类型构造函数中包装数据。在这种情况下,您可能希望AVFunctor的实例,并为Functor添加(AV a, AV b) => AV (a, b)个实例,同样为AV包裹Either {{1}} 1}}。

相关问题