我有以下函数签名,并希望实现实现它的haskell函数。
method :: (a -> (a -> b)) -> (a -> b)
即使我尝试了各种方法,但我似乎错过了一个起点。我想我可以用(>> =)这样的专长做到这一点,但我不是很确定。由于我对haskell相当新,我甚至不确定如何输出函数而不是像Int或Bool这样的值。
答案 0 :(得分:5)
让我们用“洞穴驱动的开发”来解决这个问题。我们想要定义method
,它是最高级别的函数。我们使用lambdas创建函数,因此我们可以从那里开始并留下一些漏洞。
method = \f -> #{1}
我们知道f :: (a -> (a -> b))
和我们的洞#{1} :: (a -> b)
。我们需要以某种方式使用f
来创建#{1}
类型的内容。由于我们现在想要另一个函数#{1}
,让我们使用另一个lambda
method = \f -> \a -> #{2}
现在a :: a
和#{2} :: b
。我们需要使用b
和f
类型a
和f :: (a -> (a -> b))
生成a :: a
。希望这一点变得清晰,但让我们继续分解它。
类型表示法具有函数箭头(->)
是右关联的约定,因此每当我们看到a -> (b -> c)
时,我们都可以将其视为a -> b -> c
。此外,我们在两个参数函数(如a -> b -> c
)和函数(a, b) -> c
的函数之间具有等价性。这个等价正好是curry
/ uncurry
,但在我们的案例中它很有用。
让我们通过f
将f' :: (a, a) -> b
重写为等效函数f' (a, b) = f a b
。鉴于我们总是可以使用“对角线”函数diag :: a -> (a,a)
来创建同质对,我们就完成了。我们可以使用f'
从任何b
创建(a,a)
,我们可以使用diag
从任何(a, a)
创建a
。我们想要一个b
,我们有一个a
。
method = \f -> \a -> f' (diag a)
where
f' (a, b) = f a b
diag a = (a, a)
或
method f a = f a a
因此,您可能会将method
视为缩小某个更通用的功能,而不仅仅是diagonals
。使其更加清晰的类型签名使用我们的f'
技巧:
method :: ((a, a) -> b) -> (a -> b)
method f' a = f' (a, a)