在 Haskell 中定义满足类型的函数
类型
foo :: a -> ((b -> a) -> c) -> c
考虑到我要创建一个满足此类型的函数的
...我知道 foo xy = y(\ z - > x)
满足此类型,如:类型在GHCI中,但是我该如何手动或逐步执行此最终功能?
我也知道 foo2 fg = \ x-> f(gx)
也会满足 foo2 ::(a - > b) - > (c - > a) - > c - > B
,但也不知道如何获得此功能。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这只是将拼图的匹配部分融合在一起的问题。相同的零件匹配。
foo
的类型意味着它具有两个参数:f
我们给出了,但是g
我们必须发明,以便它返回a
;幸运的是,我们已经给出了一个a
:a
作为foo
的参数和b 只是
g
的未使用参数。接下来,我们可以使用以下事实来替代和简化:
与写作相同:
在其中使用
r ...
来指示其类型为r
的表达式。另外,
s - > t - > r
与s-> (t - > r)
,因为同样,都表达了同一件事。
您的第二个问题可以以相同的方式解决。
x :: a
 表示“值 x
 有类型 a
a ”  的意思是“价值  code> a  具有类型 a
'”。可以在两个不同的角色中使用相同的名称a
 当您习惯它时,它实际上可能是一个有用的助记符。另请参见。
It's just a matter of fitting the matching pieces of a puzzle together. The same-named pieces match. The type of
foo
means it's a function with two parameters:f
we're given, butg
we must invent so that it returnsa
; fortunately, we're already given ana
:a
is given to us as a parameter offoo
, andb
is just an unused parameter ofg
.Next we can substitute and simplify, using the fact that writing this:
is the same as writing this:
where we use
r...
to indicate an expression whose type isr
.Also,
s -> t -> r
is the same ass -> (t -> r)
because, similarly,all express the same thing.
Your second question can be addressed in the same manner.
x :: a
means "the valuex
has typea
";a :: a
means "the valuea
has typea
". The same namea
can be used in two different roles; when you're accustomed to it, it can actually be quite a helpful mnemonic.See also.
下划线
_
,或一个以下划线(例如_ What What What
)开始的未定义名称,GHC将其视为您要填充的“孔”。您可以使用此信息。询问编译器期望什么类型,这可能有助于弄清楚如何迭代填充程序。值得庆幸的是,在这种情况下,它非常有用,因此我可以轻松地在GHCI中逐步进行(带有>
表示提示)。我们从孔foo = _
开始,然后收到一条消息,说
找到孔:_ :: a-> ((b - > a) - > c) - > C
。 GHC建议foo :: a - > ((b - > a) - > c) - > C
是填充孔的有效方法,实际上foo = foo
是合法的,它不是我们要寻找的答案,因为它代表了一个无限的环路。取而代之的是,我们可以查看类型并将其从上层向下分解为部分。我们从函数类型(
- >
)开始,其输入为a
并且其输出为((b - > a) - > c) - > C
。我们可以使用lambda表达式制作功能值,为a
值发明名称,例如x
,并为身体添加另一个漏洞:它现在提到我们有
X :: A
除foo
之外,还可以使用,但这还不够,因此接下来我们可以分开((b-&gt) a) - > c
进入其输入(((b - > a) - > c)
和输出c
。 (从现在开始,为了简洁起见,我还会跳过重复foo
的类型签名。)我们无法将类型变量
c
进一步分开,并且我们知道我们需要构成类型c
的值,因此我们可以查看我们的可用内容:f ::(b - > a) - > c
x :: a
foo :: a - > ((b - > a) - > c) - > c
,我们的选项是:
递归致电
foo
呼叫
f
#1很快就会使我们陷入我们所处的相同情况,因此#2就是剩下的。
f
期望类型的值b->
作为参数:因此,我们可以再次编写一个lambda:
我们产生未知类型
a
的唯一方法是使用值x :: a x :: a < /code>我们已经获得了,因此最终结果是:
可以用与您的问题完全相同的形式写入,使用少量句法糖,以及可变名称的几个不同选择:
An underscore
_
, or an undefined name beginning with an underscore such as_what
, is treated by GHC as a “hole” that you want to fill in. You can use this to ask what type the compiler is expecting, and this can be helpful in figuring out how to iteratively fill in the program. Thankfully, this is a case where it’s very helpful, so I can easily go through it step by step in GHCi (with>
indicating the prompt). We begin with a holefoo = _
:And we receive a message saying
Found hole: _ :: a -> ((b -> a) -> c) -> c
. GHC suggestsfoo :: a -> ((b -> a) -> c) -> c
as a valid way of filling in the hole, and indeedfoo = foo
is legal, it’s just not the answer we’re looking for, since it represents an infinite loop.Instead, we can look at the type and break it down into parts from the top down. We begin with a function type (
->
) whose input isa
and whose output is((b -> a) -> c) -> c
. We can make a function value using a lambda expression, inventing a name for thea
value, sayx
, and put another hole for the body:It now mentions that we have
x :: a
available to work with, in addition tofoo
, but this isn’t quite enough, so next we can take apart((b -> a) -> c) -> c
into its input((b -> a) -> c)
and outputc
. (From now on, for brevity’s sake, I’ll also skip repeating the type signature offoo
.)We can’t take apart the type variable
c
any further, and we know we need to make a value of typec
, so we can look at what we have available:f :: (b -> a) -> c
x :: a
foo :: a -> ((b -> a) -> c) -> c
So our options are:
Recursively call
foo
Call
f
#1 would quickly put us back in the same situation we’re in, so #2 is all that’s left.
f
expects a value of typeb -> a
as an argument:So again we can write a lambda:
The only way we can produce a value of the unknown type
a
is to use the valuex :: a
that we’ve been given, so the final result is this:And that can be written in exactly the same form as you put in your question, using a little syntactic sugar, and a couple different choices of variable names:
问题 1
表示 foo 必须接受一个
a
和一个类型为(b -> a) ->; 的函数。 c
并以某种方式产生一个 c.其中
a::a
和function::(b -> a) -> c
但是我们从哪里可以得到c呢?
好消息:
function
为我们创建了c
。让我们使用它。
函数::(b->a) -> c
因此,如果我们给它一个(b->a)
,我们就可以得到一个c
。因此,我们需要首先创建一个辅助函数,它接受
b
s 并给我们a
s:很好!我已经有一个
a
所以我可以使用它。我们只需要将我们刚刚创建的helper
交给function
即可:现在请注意,
helper
忽略了它的输入,因此我们可以编写我们可以使用 lambda helper 的符号:
但现在我们可以只写
(\_ -> a)
而不是 helper:最后,让我们将
function
缩写为f
:问题2
好的,这次我们需要制作一个
b
。我们给出了一个c
和几个函数,用于将a
s 转换为b
s,将c
s 转换为a
s:嗯,唯一能给我们
b
的是make_b_from_a
:但现在我们需要一个
a
>,但我们可以使用make_a_from_c
为此,我们已经有了一个c
:让我们缩短名称。我将把
(c->a)
称为f
因为我们在另一个之前使用它,我将其称为g:
我们可以使用 lambda 获取最后一个参数:
Question 1
says that foo has to take an
a
and a function with type(b -> a) -> c
and somehow produce a c.where
a::a
andfunction::(b -> a) -> c
but where can we get the c from?
Good news:
function
makesc
s for us.Let's use that.
function::(b->a) -> c
so we can get ac
if we give it a(b->a)
.So we need to first make a helper function that takes
b
s and gives usa
s:That's fine! I already had an
a
so I could use that. We just need to handfunction
thehelper
we just made:Now notice that
helper
ignores its input, so we could writeAnd we can use lambda notation for helper:
But now we could just write
(\_ -> a)
instead of helper:And finally, lets abbreviate
function
asf
:Question 2
OK, this time we need to make a
b
. We're given ac
and a couple of functions for turninga
s intob
s andc
s intoa
s:Well, the only thing that can give us a
b
ismake_b_from_a
:but now we need an
a
, but we can usemake_a_from_c
for that, and we already have ac
:Let's shorten the names. I'm going to call the
(c->a)
onef
because we use it before the other one, which I'll callg
:We can take the last argument using a lambda: