我有以下函数签名,并希望实现一个实现它的 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)aba
method = \f -> \a -> f' (diag a)
where
f' (a, b) = f a b
diag a = (a, a)
或者
method f a = f a a
因此,您可能会将某个更通用的功能缩小method为仅作用于. 使这一点更加清晰的类型签名使用了我们的技巧:diagonalsf'
method :: ((a, a) -> b) -> (a -> b)
method f' a = f' (a, a)