我正在尝试写一个 arrow使用常规函数并将它们转换为对抽象值的计算的转换器。如果我们有一个“源”箭头,
f :: Int -> Int
f x = x + 1
那么目标是让 f 处理提升的 [原文如此?] 抽象值类型,在这个例子中
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 节。
非常非常感谢你!
最佳答案
让我看看我是否明白你在这里的目的。你有一个类型 AV a
它描述了产生 a
类型的东西的计算,其中可以以允许检查的方式保留该计算的结构。您想要一种将任意函数提升到 AV
上的操作的方法。 ,保留结构,而不必为每个操作创建特殊情况。
通常,为了将函数提升到某种结构中,可以使用 Functor
和 Applicative
.但是,这样做的直接方法涉及转换结构并直接应用提升的函数,而不是将函数应用程序保留为结构的一部分。
你想要的更尴尬,这就是原因:
假设我们有一些我们想要提升的函数,以及两个适当类型的抽象值来应用它:
x :: AV A
x = ...
y :: AV B
y = ...
f :: A -> B -> C
f = ...
假设存在一个函数
liftAV2
这就是你想要的。我们预计 lift2 f
的类型成为 AV A -> AV B -> AV C
,就像 liftA
为 Applicative
.稍后,我们要检查使用
lift2 f
产生的计算。 ,通过恢复 f
的值, x
, 和 y
.假设现在我们只想提取第一个参数。假设存在一个函数 extractArg1
这样做,使得 extractArg1 (liftAV2 f x y)
= x
. extractArg1
的类型是什么?在这里,在上下文中,我们知道它应该具有类型 AV C -> AV A
.但它一般有什么类型?类似 AV c -> AV a
?这是错误的,因为结果不只是任何类型 a
,它是用于构造 AV c
的任何类型值(value)。假设我们正在操作的值是使用 liftAV2 f
的结果构建的,我们知道有问题的类型存在,但我们没有办法找到它。这是我们进入土地的地方,足够恰当,存在类型 .诚实地使用它们,不少于,而不是像通常那样将它们与类型类一起使用。
您可能可以通过一些努力来完成您所追求的目标,但这已经进入了相当先进的领域。你会想要使用 GADT 对于初学者来说,虽然我认为你可能已经这样做了。使用存在类型也往往非常笨拙,因为您只能在有限的上下文中知道它们是什么。
在您的具体情况下,提供
AV
可能更容易两种类型参数:一种表示计算的最终类型,一种表示计算的结构,例如:data f :$ x = ...
data AV structure result where
...
AVApply :: AV f (a -> b) -> AV x a -> AV (f :$ x) b
然后,为了检查计算,您可以查看第一种类型以了解您拥有什么;为了构建计算,您可以查看第二个以确保类型匹配。评估函数的类型类似于
AV t a -> a
,扔掉结构。如果您需要拆开结构以便漂亮地打印它,您还可以使用结构类型“解包”计算,丢弃结果类型。
关于generics - Haskell 中的泛型类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5840610/