我有以下代码,概述了布尔和算术表达式的语言:
data Exp a where
Plus :: Exp Int -> Exp Int -> Exp Int
Const :: (Show a) => a -> Exp a
Not :: Exp Bool -> Exp Bool
And :: Exp Bool -> Exp Bool -> Exp Bool
Greater :: Exp Int -> Exp Int -> Exp Bool
上述语言的评估功能具有以下类型:
eval :: Exp a -> a
我试图了解eval
函数可以返回什么类型。上面的代码使用GADT,这些GADT支持根据构造函数的类型签名定义Exp a类型。
构造函数的返回类型并不总是Exp a。我相信类型eval
可以返回包括Int,Bool或实现Show的任何类型的值。但是,eval
是否可以返回除我之前提到的三种类型之外的其他任何类型(因为函数的返回类型为a
)?任何见解都会受到赞赏。
答案 0 :(得分:3)
function sendOrder() {
var ui = SpreadsheetApp.getUi();
var response = ui.alert('Are you sure you want to send the order?',
ui.ButtonSet.YES_NO);
var deliveryDate = ui.prompt('Delivery date:');
// Process the user's response.
if (response == ui.Button.YES) {
var s = SpreadsheetApp.getActive().getSheetById('1pON34oXVhlpC8goyBxfu6-Gw92tgQBUVUpskZUtgp4E');
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getActiveSheet().getDataRange();
var range = s.getRange('A1:C102');
var to = "example@example.com";
var body = '';
var htmlTable = SheetConverter.convertRange2html(range);
var body = "Here is the table:<br/><br/>" +
htmlTable +
"<br/><br/>The end."
MailApp.sendEmail(to, 'Subject', body, {
htmlBody: body
});
};
SpreadsheetApp.getUi().alert('Yeah! Your order has been sent :)');
}
是可能具有许多个可能功能的类型。例如,一个可能不是您认为的“ Exp a -> a
函数”的有效函数就是
eval
函数的 image 是它可以返回的一组值。此示例说明,尽管返回类型为foo :: Exp a -> a
foo (Plus _ _) = 3
foo (Const x) = x
foo (Not _) = True
foo (And _ _) = True
foo (Greater _ _) = True
,但您期望的函数foo
和eval
具有不同的图像。
您实质上是在问forall a. a
类型的函数的所有可能图像的 union 是什么。这在很大程度上取决于Exp a -> a
的实际定义。按照当前的定义,这将是Exp
,Int
和Bool
的并集。
Show a => a
类型构造函数能够定义无人居住的类型。类型Exp
存在,即使您尚未定义可以创建该类型的值的构造函数。由于您无法为任何潜在的Exp (Int -> Int)
函数提供类型Exp (Int -> Int)
的值,因此它也不会影响任何此类函数的图像。
更改eval
的定义以包含此类构造函数将增加可以传递给类型Exp
的函数的值集,从而增加图像中可能出现的值集这样的功能。
答案 1 :(得分:0)
要清楚,给定您在上面的Exp
的定义,答案是“是”:任何类型签名为eval :: Exp a -> a
的函数只能返回Int
类型的(定义)值,Bool
或其他带有Show
实例的类型。因为可以为任何类型(*
类型)指定一个Show
实例,所以从技术上讲,eval
可以返回任何类型,但是在具有固定{{ 1}}个实例,Show
将仅限于从这组类型中返回值。
您可以看到,这必须满足以下条件。假设eval
为某个表达式eval e
返回了某个固定类型t
的值。根据{{1}}的类型签名,这意味着e
必须具有类型eval
。但是,数据类型声明是“封闭的”,这意味着e
声明中给出的构造函数集是详尽的,它们代表构造Exp t
类型的(定义)值的唯一方法。从一组构造函数中可以明显看出,类型data Exp a
的唯一可能值是出现在构造函数签名最右边的那些值:Exp a
,Exp a
和{{1} },约束为Exp Int
。因此,这是Exp Bool
唯一可能的类型,这意味着Exp a
必须是Show a
,e
或其他满足约束{{1}的其他t
}。
一如既往地对Haskell类型进行推理,我们在考虑未定义/底值时必须格外小心。如果您认为“返回未定义的值”是有意义的,那么实际上Int
可以“返回”任何类型的未定义值,即使没有Bool
实例也是如此。例如,以下将进行类型检查:
a
但是,如果您问这个问题的原因是要确定您是否曾经遇到过表达式Show a
可能意外地具有eval
,Show
以外的其他类型,或某些您需要处理的stupid :: Exp (Int -> Int)
stupid = eval undefined
,然后否。 GADT的形式限制了签名eval e
中可能的类型Int
。