gpt4 book ai didi

haskell - 是否可以在 Haskell 中使用可调用对象定义类型?

转载 作者:行者123 更新时间:2023-12-03 15:17:56 27 4
gpt4 key购买 nike

我对 haskell 很陌生,对它的类型系统还不太熟悉。我想知道,如果有能力定义类型(数据类型?),哪些实例可以被称为函数?

类似物是

__call__ 

Python 中的方法或类方法
operator() 

在 C++ 中。 (维基百科中给出了“函数对象”一词的更多示例)。

应用这种结构的例子是 Polynom。该对象由其系数列表定义,即我想要这样的类型:
data Num a => Polynom a = Polynom [a]
deriving (...)

现在我当然可以定义函数
callPoly :: Num a => (Polynom a) -> a -> a
callPoly p x = ... -- implementation: extract coefficients of p,
-- construct polynomial and call it on x

(在这里我不打扰,能够在浮点数上调用具有 Int 系数的多项式......这只是技术细节)

现在我可以在我的多项式上调用它(在交互式提示中):
let myPoly = Polynomial [1 2 3]
let applicationResult = callPoly myPoly 3

但这种方式并不太花哨。希望能够直接将多项式称为
let applicationResult = myPoly 3

那么问题来了:可以定义这样的Polynomial类型,哪些对象(实例)可以被调用(作为函数使用)?可能这种模式可以以其他方式实现,而不涉及“数据”?可能是一些玩函数类型或smth。别的?

当然,这个想法不仅可以应用于多项式。实际上,对于任何必须“具有类型”并具有“一些附加数据”的函数(在多项式的情况下 - 它是系数)。

或者,如果这是不可能的,那么是否有一些特定的原因或者它只是不受支持?

P.S.:在我看来,直接方法(如上所述)是不可能的,因为可调用的 myPoly 必须是类型(Int -> Int)。但是类型 (Int -> Int) 不能附加任何数据(例如多项式系数)。但我想确定,我是对的。

最佳答案

熟悉 C++“函数对象”概念是件好事,因为这是对 Haskell 的关于可以用普通旧函数做什么的想法的一个很好的介绍……特别是,柯里化(Currying)、部分应用和将函数作为参数传递给其他函数.

在 C++ 中,您的代码将类似于:

class Polynomial {
int coefficients[];
public:
Polynomial(int coefficients[]) { /* ... */ }
int operator() (int value) { /* ... */ }
};

int coefficients[] = {1, 2, 3};
Polynomial(coefficients)(4); // note the syntax here!

这从根本上表达了一个单一的纯函数:一个多项式评估器,它采用一系列系数和一个值。它可以很容易地用 C++ 表示为:

int evaluatePolynomial(int coefficients[], int value);

int coefficients[] = {1, 2, 3};
evaluatePolynomial(coefficients, 4);

但是这种形式不像以前的形式那样被 curry 。 curry 形式的好处是你可以说:

Polynomial p = Polynomial(coefficients);
p(4);
p(5);
p(6);

代替:

evaluatePolynomial(coefficients, 4);
evaluatePolynomial(coefficients, 5);
evaluatePolynomial(coefficients, 6);

好的。所以我们把这个“函数对象”看作是一个面向对象的编程概念——一个伪装成函数的对象——但是现在让我们忘记对象。如果您在 Haskell 中查看它,它只是一个函数,不需要任何用户定义的数据类型即可很好地表达:

polynomial :: Num a => [a] -> a -> a

您可以将其称为“通常”(与上面的 evaluatePolynomial() 一样),同时将其应用于两个参数:

polynomial [1, 2, 3] 4

但是因为 Haskell 函数是柯里化(Currying)的,你可以部分应用(如 Polynomial 函数对象):

do
let p = polynomial [1, 2, 3]
print (p 4)
print (p 5)
print (p 6)

十分简单。现在,如果你想做一些更接近 C++ 的事情,你有一个特定的数据类型来代表你的 Polynomial函数对象,你可以这样做......

newtype Polynomial a = P (a -> a)  -- function object
mkPolynomial :: Num a => [a] -> Polynomial a -- constructor

...但是这种额外的复杂性并没有真正提供任何好处。您会立即注意到 Polynomial 并没有什么特别之处。 ,它只是包装了一个常规函数,所以你最终不得不再次解开它,比如:

do
let (P p) = mkPolynomial [1, 2, 3]
print (p 4)
print (p 5)
print (p 6)

简而言之,你越是纯粹地根据函数而不是对象来构建你的思维,你的 Haskell 代码最终会变得越简单和越惯用。

关于haskell - 是否可以在 Haskell 中使用可调用对象定义类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7902520/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com