我如何手动确定表达式的类型,而不是在GHCi中使用class StringSignal : public QObject {
Q_OBJECT
public:
Q_SIGNAL void signal(const QString &);
};
void MainWindow::initializeInterests(const QStringList &personsIn) {
auto in = personsIn;
std::sort(in.begin(), in.end());
QStringList persons;
persons.reserve(in.size());
for (int i = 0; i < persons_comboBox_->count(); ++i) {
auto const combo = persons_comboBox->itemText(i);
if (std::binary_search(in.begin(), in.end(), combo))
persons << combo;
}
QtConcurrent::run([persons = std::move(persons), w = this](){
StringSignal source;
connect(&source, &StringSignal::signal, w, [w](const QString & person){
w->initalizeMBox->setText(
QStringLiteral("%1 <div><img src=...> %2: %3.</div>")
.arg(w->initalizeMBox->text())
.arg(tr("Interests analyzed for the person"))
.arg(person)
);
});
for (auto &person : persons) { // persons is const
// create a specific object etc.
QThread::sleep(1); // let's pretend we work hard here
source.signal(person);
}
});
}
?
对于基本表达式,我们可以通过查看表达式并提出某种类型来实现。
对于像:type
这样的更复杂的表达式,是否存在某种算法方法?
答案 0 :(得分:5)
知道Hindle-Milner肯定是可能的,但在很多情况下,只需要一点直觉就可以得到正确的结果。
正如你所说,对于基本表达式来说,这很容易。假设您有一个像f :: Integer -> Integer -> Integer
这样的简单函数。将此函数应用于Integer
(例如f 42
之类的内容)时,您可以立即看到其类型为Integer -> Integer
。微不足道的。
一旦开始引入类型变量和约束,乐趣就开始了。尽管基本概念仍然相同 - 将a -> b
类型的函数应用于类型为a
的表达式会产生b
- 您必须小心不要混淆所有输入变量,不要忘记约束。
让我们以(.) . (.)
为例,逐步完成它。
((.) (.)) (.)
- 这是(.)
到(.)
的应用,其结果将应用于另一个(.)
。让我们只关注第一个应用程序,然后再处理第二个应用程序。(.)
的类型为(b -> c) -> (a -> b) -> a -> c
,在这种情况下我们将其应用于自身 - 因此,我们必须统一第一个参数的类型(即。{{ 1}})类型为b -> c
。这是你必须要小心你的类型变量的部分 - 因此,我将第二个(以及后来甚至第三个)(.)
的类型变量重命名为(.)
- 这有对实际类型没有影响,它只是让我们以后不会迷路。(b1 -> c1) -> (a1 -> b1) -> a1 -> c1
类型为b -> c
的类型。 (b1 -> c1) -> (a1 -> b1) -> a1 -> c1
与b
统一,b1 -> c1
与其他人c
统一。由于对任何类型变量都没有约束,我们不需要关心它们。(a1 -> b1) -> a1 -> c1
和b
所代表的实际类型,我们可以将它们替换为c
的类型(忽略第一个参数,因为我们刚刚应用了)我们最终会得到这个:(.)
(a -> b1 -> c1) -> a -> (a1 -> b1) -> a1 -> c1
。(.)
的类型(我将其类型变量重命名为(.)
,a2
和b2
,因此它变为{{1 } {}与c2
。这又是一件容易的事。 (b2 -> c2) -> (a2 -> b2) -> a2 -> c2
变为(a -> b1 -> c1)
,a
变为b2 -> c2
,最后b1
变为a2 -> b2
。c1
的参数,我们将获得a2 -> c2
并完成。< / LI>
忽略不同的名称,您可以看到这与使用(.)
获得的结果完全相同。
我希望这会有所帮助。
答案 1 :(得分:2)
这是类型推断的图形视图。 我们想找到
的类型(.) . (.) :: ?
为此我们首先列出每个变量的类型,使用新的类型变量。放下大量括号也有助于避免在接下来的步骤中出现错误。
(.) :: (a1 -> a2) -> ((a0 -> a1) -> (a0 -> a2))
(.) :: (b1 -> b2) -> ((b0 -> b1) -> (b0 -> b2))
(.) :: (c1 -> c2) -> ((c0 -> c1) -> (c0 -> c2))
然后我们对齐类型,以便参数类型与函数类型匹配。首先,对于一个更简单的示例,如果我们想要找到f x y
的类型
f :: a -> a -> a
x :: b
y :: c
然后我们将对齐类型如下
f :: a -> (a -> a)
x :: b -- First argument
y :: c -- Second argument
-- ^ Result type
因为x
是f
的第一个参数,而y
是第二个参数。这告诉我们将a = b
和a = c
等同,结果类型为a
这是原始问题的图表,为拉伸表达式添加了大量空白,以便它们匹配。
(.) :: (a1 -> a2 ) -> (a0 -> a1 ) -> (a0 -> a2)
(.) :: (b1 -> b2) -> ((b0 -> b1) -> (b0 -> b2))
(.) :: (c1 -> c2) -> ((c0 -> c1) -> (c0 -> c2))
-- ^ Result
通过查看这些表格的列,我们在类型之间获得以下等式:
a1 = (b1 -> b2)
a2 = ((b0 -> b1) -> (b0 -> b2))
a0 = (c1 -> c2)
a1 = ((c0 -> c1) -> (c0 -> c2))
从第一个和最后一个,我们进一步推导出另外两个方程式
b1 = (c0 -> c1)
b2 = (c0 -> c2)
结果类型为(a0 -> a2)
,即替换后:
(c1 -> c2) -> (b0 -> c0 -> c1) -> (b0 -> c0 -> c2)