我有以下函数签名,并希望实现一个实现它的 haskell 函数。
method :: (a -> (a -> b)) -> (a -> b)
尽管我尝试了各种方法来做到这一点,但我似乎错过了一个起点。我想我也许可以用 (>>=) 之类的壮举来做到这一点,但我不太确定。由于我对haskell 相当陌生,我什至不太确定如何输出函数而不是像Int 或Bool 这样的值。
让我们使用 la Agda 的“洞驱动开发”来解决这个问题。我们想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
. 此外,我们在两个参数函数 likea -> b -> c
和 pairs函数之间存在等价性(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)