How to use a proxy server in Haskell? (possibly using an extension of a higher rank)

Over the past few months, I have made some serious efforts to learn Haskell - previously, I was a seemingly endless beginner with very limited knowledge of the basics. Trying to inject my new knowledge into projects with a few steps because of hello-world, I still think that I want to use proxy-like templates based on type classes. The first couple of times when I found out why it didn’t work, I rejected it as “OK - I can’t find any idiomatic Haskell replacement, but the problem is that I use the wrong approach for the language.” But I found that I really don't like the inability to do proxy-like things.

Trying to get a deeper understanding of why I could not use proxies, after many experiments, I finally realized that with a higher rank GHC extension, maybe I can have proxies. But I still can't get it to work, and I'm not sure why.

Here is the code for the best I 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 for a problem 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)

A function f0(if I understand types of a higher rank correctly), a polymorphic function is passed as a parameter with a type Gen ga => ga Char -> [(r, ga Char)]. In terms of translating to C, the caller passed a pointer to a function, but did not specify a vtable pointer.

proxyNotL - PROXY gb Char, instance Gen nestedgen => Gen (PROXY nestedgen) where ..., PROXY gb Char Gen gb Gen, call_f0.

, , GHC : " vtable, f0... hmmm... , PROXY gb Gen, PROXY gb, , ".

... GHC ga PROXY gb? GHC , ?

, , ?

+5
2

, f0 , forall ga. :

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)]

GHC forall ga. , , , ga , GHC , , ga PROXY gb.

, RankNTypes , .

+5

, "" . , , Gen.

Gen typeclass

class Gen g where
    get :: g x -> [(x, g x)]

forall g. Gen g => g x (). , a, get, :

a :: forall g. Gen g => g x
get a :: forall g. [(x, g x)]

, , , g x, , , [(x, g x)]; , g, :

newtype G x = G { unG :: [(x, G x)] }

g Gen

toG :: Gen g => g x -> G x
toG = G . map (second toG) . get

Gen

instance Gen G where
    get (G as) = as

- , ?

+1

All Articles