如何实现此高阶函数

时间:2018-10-09 17:17:18

标签: haskell functional-programming

我是函数式编程的新手,我正在尝试解决以下问题;


给出类型

$secret = '6LclC3QUAAXXXXXXXXXXXXXXXX5hrAxfHXXXiMH';
$response = $_POST['g-recaptcha-response'];
$remoteip = $_SERVER['REMOTE_ADDR'];
$data = array(
            'secret' => $secret,
            'response' => $response,
            'remoteip' => $remoteip
);
$options = array(
            'http' => array(
                'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
                'method' => 'POST',
                'content' => http_build_query($data)
            )
);
$context = stream_context_create($options);
$res = json_decode(file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context), true);

实现以下高阶函数

type Cont r a = (a -> r) -> r

第一步是简化类型,从而得出:

mapReader :: (a -> b) -> (Cont r a) -> Cont r b

接下来,定义此功能中需要提供的参数。这些参数是三个函数,所以我们得到

mapReader :: (a -> b) -> ((a -> r) -> r) -> (b -> r) -> r

从这里,我们可以定义以下类型:

mapReader :: (a -> b) -> ((a -> r) -> r) -> (b -> r) -> r
mapReader f g h = _1

但是现在我被卡住了。有两个产生r的函数,其中一个包含另一个函数(a-> r)。如何开始定义r?任何提示都非常感谢!

3 个答案:

答案 0 :(得分:5)

我们有

f :: a -> b
g :: (a -> r) -> r
h :: b -> r

我们需要

_1 :: r

我们可以通过两种方式制作rgh

让我们尝试使用hh接受类型为b的参数。获得其中之一的唯一方法是使用ff接受类型为a的参数,并且...我们无法获得其中之一。

因此,现在让我们尝试使用g代替:

mapReader f g h = g _2

被告知

_2 :: a -> r

由于我们正在构造函数,因此可以照常应用lambda抽象:

mapReader f g h = g (\a -> _3)

a :: a
_3 :: r

但是等一下...现在我们有一个a ,所以我们可以回到第一次尝试:

mapReader f g h = g (\a -> h (f a))

或更紧凑地说,

mapReader f g h = g (h . f)

如果不是重新尝试第一次尝试,而是再次使用第二种方法 呢?

mapReader' f g h =
  g (\a1 -> g (\a2 -> _4))

_4 :: r

您可以永远这样,但也可以通过两种不同的方式在这里停留:

mapReader2 f g h =
  g (\_ -> g (h . f))

mapReader3 f g h =
  g (\a1 -> g (\_ -> h (f a1)))

好!这是三个具有不同类型的 different 函数,如图所示,该方法可用于生成无限的函数族!您如何确定想要哪一个?您必须考虑意图。 g的论点是连续性,因此您想用传递的内容g来构成一个函数,而不是多次调用g。因此mapReader是“正确”的答案。

更准确地说,mapReader应该映射连续性 functor 的形态射影。尤其需要

mapReader id = id

也就是说,

mapReader id g h = g (h . id)
  = g h

对于正确的定义,这是无条件的,但对于其他任何定义都不是。

答案 1 :(得分:1)

首先查看您可以使用这三个参数做什么。

  1. 您可以撰写fhh . f :: a -> r
  2. 您可以将g应用于h . fg (h . f) :: r

所以您可以简单地说mapReader f g h = g (h . f)。这里没有足够的信息来指定r是什么。这完全取决于什么 自变量gh被赋予mapReader

答案 2 :(得分:0)

所以你有

f ::  a -> b
h ::       b -> r
g :: (a ->      r) -> r

还有前向功能组合运算符,

(>>>) :: (a -> b) -> (b -> r) -> (a -> r)

和反向应用程序运算符,

(&) :: t -> (t -> r) -> r

这样

f >>> h :: ......... -- what?

(f >>> h) & g :: ......... -- what else?

您能仅根据它们的类型来提出(>>>)(&)的定义吗?


让我让您开始第一个。

(>>>) ::   (a -> b)    -> (b -> r)     -> (a  -> r)

表示

(>>>) (f :: a -> b)    :: (b -> r)     -> (a  -> r)
(>>>) (f :: a -> b) (g ::  b -> r)     :: (a  -> r)
(>>>) (f :: a -> b) (g ::  b -> r)  (x ::  a) :: r

所以我们再次写下来

f :: a -> b
g ::      b -> r
x :: a
f x ::    b
g (f x) ::    ....

就是这样。

我们在这里使用的最重要的规则是

x   :: a
f   :: a -> r
f x ::      r