如何在Haskell中使用代理? (可能使用更高等级的类型扩展) [英] How to use a proxy in Haskell? (probably using a higher-rank types extension)
问题描述
尝试获取更深入的理解为什么我不能使用代理服务器,经过大量的实验后,我终于发现,使用GHC更高等级类型的扩展,也许我可以有代理服务器。但是我仍然无法完成它的工作,我不知道为什么。
这是我管理的最好的代码...
p> { - #LANGUAGE RankNTypes# - }
模块测试其中
- 简单类型类基于解析器组合器。
class Gen g where
get :: g x - > [(x,gx)]
实例Gen []其中
get [] = []
get(x:xs)= [(x,xs)]
- 代理类型 - 保存一对包含...
- - 某种支持Gen $ b $的类型的值 - - 一个函数用于指示何时应该跳过一个项目
newtype PROXY nestedgen x =代理(nestedgen x,x - > Bool)
proxyskip :: Gen nestedgen => PROXY nestedsted r - > Bool
proxyskip(Proxy(g,predf))= case得到g
[] - >假
((r,_):_) - > predf r
proxyget :: Gen nestedgen => PROXY nestedsted r - > [(r,PROXY nestedgen r)]
proxyget pr @(Proxy(sg,predf))= if proxyskip pr
then [(r2,g2)| (代理(g1,predf))]
else [(r3,Proxy(g3,predf))| (r3,g3)< - get sg]
- PROXY的Gen的实例 - 在适当的地方获得跳过的项目
实例Gen nestedgen => Gen(PROXY nestedgen)其中
get = proxyget
- 测试解析器
- 获取指定数量的项目,将它们作为列表提供(在$ b $内b - 非确定性(结果,状态)对的列表)。
getN :: Gen g => Int - > g x - > [([x],g x)]
getN n g | (n <0)=错误负n
| (n == 0)= [([],g)]
| True = [(r1:r2,g2)| (r1,g1)< - get g,(r2,g2)< - getN(n-1)g1]
- 在PROXY中包装一些任意的parser字母'l'
proxyNotL :: Gen gb => gb Char - > PROXY gb Char
proxyNotL gg =(Proxy(gg,\ ch - >(ch / ='l')))
call_f0 :: Gen gb => (Gen ga => ga Char - > [(r,ga Char)]) - > gb Char - > [(r,PROXY gb Char)]
call_f0 f0 g0 = f0(proxyNotL g0)
test :: Gen gb => (Gen ga => ga Char - > [(r,ga Char)]) - > gb Char - > [(r,gb Char)]
test f0 g0 = [(r,g2)| (r,Proxy(g2,_))< - call_f0 f0 g0]
发生在 call_f0 f0 g0 = f0(proxyNotL g0)
...
<$ c编译测试(Test.hs,Test.o)
Test.hs:44:21:
无法推断(ga〜PROXY gb)$ b来自上下文(Gen gb)的
$ b由
的类型签名绑定call_f0 :: Gen gb =>
(Gen ga => ga Char - > [(r,ga Char)])
- > gb Char
- > [(r,PROXY gb Char)]
at Test.hs:44:1-33
`ga'是一个刚性类型变量,由
绑定
的类型签名call_f0 :: Gen gb =>
(Gen ga => ga Char - > [(r,ga Char)])
- > gb Char
- > [(r,PROXY gb Char)]
at Test.hs:44:1
预期类型:ga Char
实际类型:PROXY gb Char
在返回类型a调用`proxyNotL'
在`f0'的第一个参数中,即`(proxyNotL g0)'
在表达式中:f0(proxyNotL g0)
查看有问题的功能...
call_f0 :: Gen gb => (Gen ga => ga Char - > [(r,ga Char)]) - > gb Char - > [(r,PROXY gb Char)]
call_f0 f0 g0 = f0(proxyNotL g0)
f0
函数是(如果我正确理解更高级别的类型)作为参数传递的多态函数,类型为 Gen ga => ga Char - > [(r,ga Char)]
。在转换为C的术语中,调用者传递了一个函数指针,但没有提供vtable指针。
proxyNotL
函数返回类型为
PROXY gb Char
的东西,并且有一个实例声明实例Gen nestedgen => Gen(PROXY nestedgen)其中...
,这样 PROXY gb Char
实例 Gen
提供了 gb
实例 Gen
,它根据 call_f0
基本上,据我所知,GHC应该说我可以提供 f0
需要...嗯...是的,因为 PROXY gb
实例 Gen
,并且我知道 PROXY
和 gb
,是的,我可以。
...为什么GHC拒绝统一 ga
和 Proxy gb
?为什么GHC拒绝调用一个多态函数,并且该函数的多态类型应该支持一个参数值?
您只需明确指定函数 f0
必须通过在您的类型签名中添加通用量词 forall ga。
来变得多态:
call_f0 :: Gen gb => (其中ga = Gen(>> ga Char - > [(r,ga Char)]) - > gb Char - > [(r,PROXY gb Char)]
test :: Gen gb => (其中ga = Gen(>> ga Char - > [(r,ga Char)]) - > gb Char - > [(r,gb Char)]
否则,GHC会将一个隐含的在最外层,即调用者可以决定应该使用哪一个
ga
,而GHC已经正确地推断出这些函数必须能够自行选择 ga
应该是 PROXY gb
。
$ b $换句话说,当使用
RankNTypes
来要求多态参数时,您必须始终使用明确的量词来指定它。 For the last few months, I've been putting some serious effort into learning Haskell - previously, I was a seemingly perpetual newbie with a very limited knowledge of the basics. While trying to put my new knowledge into practice on few-steps-up-from-hello-world projects, I keep finding that I want to use proxy-like patterns based on type classes. The first couple of times, when I figured out why it wasn't working, I dismissed it as "OK - I may not find a single idiomatic Haskell replacement, but odds are the problem here is that I'm using the wrong approach for the language". But what I've found is that I really really don't like not being able to do proxy-like things.
Trying to get a deeper understanding of why I couldn't use a proxy, after lots of experimenting, I finally figured out that with GHCs higher rank types extension, perhaps I can have proxies. But I still can't quite make it work, and I'm not sure why.
Here is the code for the best I've managed...
{-# LANGUAGE RankNTypes #-}
module Test where
-- Simple type class based on parser combinators.
class Gen g where
get :: g x -> [(x, g x)]
instance Gen [] where
get [] = []
get (x:xs) = [(x, xs)]
-- Proxy type - holds a pair containing...
-- - a value of some type that supports Gen
-- - a function to indicate when an item should be skipped
newtype PROXY nestedgen x = Proxy (nestedgen x, x -> Bool)
proxyskip :: Gen nestedgen => PROXY nestedgen r -> Bool
proxyskip (Proxy (g, predf)) = case get g of
[] -> False
((r,_):_) -> predf r
proxyget :: Gen nestedgen => PROXY nestedgen r -> [(r, PROXY nestedgen r)]
proxyget pr@(Proxy (sg, predf)) = if proxyskip pr
then [(r2, g2) | (_, g1) <- get sg, (r2,g2) <- proxyget (Proxy (g1, predf))]
else [(r3, Proxy (g3, predf)) | (r3,g3) <- get sg]
-- Instance of Gen for PROXY - get skips items where appropriate
instance Gen nestedgen => Gen (PROXY nestedgen) where
get = proxyget
-- Test "parser"
-- Get the specified number of items, providing them as a list (within
-- the list of nondeterministic (result, state) pairs).
getN :: Gen g => Int -> g x -> [([x], g x)]
getN n g | (n < 0) = error "negative n"
| (n == 0) = [([], g)]
| True = [(r1:r2, g2) | (r1, g1) <- get g, (r2, g2) <- getN (n-1) g1]
-- Wrap some arbitrary "parser" in a PROXY that skips over the letter 'l'
proxyNotL :: Gen gb => gb Char -> PROXY gb Char
proxyNotL gg = (Proxy (gg, \ch -> (ch /= 'l')))
call_f0 :: Gen gb => (Gen ga => ga Char -> [(r, ga Char)]) -> gb Char -> [(r, PROXY gb Char)]
call_f0 f0 g0 = f0 (proxyNotL g0)
test :: Gen gb => (Gen ga => ga Char -> [(r, ga Char)]) -> gb Char -> [(r, gb Char)]
test f0 g0 = [(r, g2) | (r, Proxy (g2, _)) <- call_f0 f0 g0]
The last remaining error occurs on the line call_f0 f0 g0 = f0 (proxyNotL g0)
...
[1 of 1] Compiling Test ( Test.hs, Test.o )
Test.hs:44:21:
Could not deduce (ga ~ PROXY gb)
from the context (Gen gb)
bound by the type signature for
call_f0 :: Gen gb =>
(Gen ga => ga Char -> [(r, ga Char)])
-> gb Char
-> [(r, PROXY gb Char)]
at Test.hs:44:1-33
`ga' is a rigid type variable bound by
the type signature for
call_f0 :: Gen gb =>
(Gen ga => ga Char -> [(r, ga Char)])
-> gb Char
-> [(r, PROXY gb Char)]
at Test.hs:44:1
Expected type: ga Char
Actual type: PROXY gb Char
In the return type of a call of `proxyNotL'
In the first argument of `f0', namely `(proxyNotL g0)'
In the expression: f0 (proxyNotL g0)
Looking at the problematic function...
call_f0 :: Gen gb => (Gen ga => ga Char -> [(r, ga Char)]) -> gb Char -> [(r, PROXY gb Char)]
call_f0 f0 g0 = f0 (proxyNotL g0)
The f0
function is (if I understand higher rank types correctly) a polymorphic function passed as a parameter, with type Gen ga => ga Char -> [(r, ga Char)]
. In translating-to-C terms, the caller has passed in a function pointer, but has not supplied the vtable pointer.
The proxyNotL
function returns something of type PROXY gb Char
, and there's an instance declaration instance Gen nestedgen => Gen (PROXY nestedgen) where ...
, so that PROXY gb Char
instances Gen
provided gb
instances Gen
, which it does according to the type signature for call_f0
.
Basically, as far as I can tell, GHC should say "can I provide the vtable that f0
requires... hmmm... yes, since PROXY gb
instances Gen
, and I know about PROXY
and gb
, yes I can".
So... why is GHC refusing to unify ga
and Proxy gb
? Why is GHC refusing to call a polymorphic function, with an argument value that should be supported by the polymorphic type of that function?
Or alternatively, what am I completely misunderstanding here?
You just need to explicitly specify that the function f0
must be polymorphic by adding the universal quantifier forall ga.
to your type signatures:
call_f0 :: Gen gb => (forall ga. Gen ga => ga Char -> [(r, ga Char)]) -> gb Char -> [(r, PROXY gb Char)]
test :: Gen gb => (forall ga. Gen ga => ga Char -> [(r, ga Char)]) -> gb Char -> [(r, gb Char)]
Otherwise, GHC will put an implicit forall ga.
at the outermost level, meaning that the caller would get to decide which ga
should be used, while GHC has correctly deduced that these functions must be able to choose themselves that ga
should be PROXY gb
.
In other words, when using RankNTypes
to require a polymorphic argument, you must always use an explicit quantifier to specify this.
这篇关于如何在Haskell中使用代理? (可能使用更高等级的类型扩展)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!