运营商<>究竟如何?在Purescript工作?

时间:2018-04-18 08:18:53

标签: type-conversion purescript

作为Purescript的新手,我正在努力弄清楚为什么以下代码(取自“PureScript By Example”)的工作原理如下:

> flip (\n s -> show n <> s) "Ten" 10
"10Ten"

这对我来说很有意义:以相反的顺序翻转第一个参数(lambda表达式)及其第二个和第三个参数,从而产生连接的字符串。

但我想知道为什么我们会用这个片段得到以下回复:

> flip (\n s -> show n <> s) 10 "Ten"

Could not match type Int with type String

以下是我的思路:运算符<>实际上是Data.Semigroup.append的简写,调用时n推导为StringData.Semigroup的实例})和s推导为Int。那么为什么<>无法将Int附加到String? (我想因为它是正确联想的,但我不确定......)

2 个答案:

答案 0 :(得分:2)

要清楚......

flip (\n s -> show n <> s) "Ten" 10  == show 10 <> "Ten"
flip (\n s -> show n <> s) 10 "Ten"  == show "Ten" <> 10

(<>)Data.Semigroup.append的别名)的类型为:

append :: a -> a -> a

也就是说,它的参数必须属于同一类型(它们必须匹配)。但是在您的第二次通话中,您将StringInt传递给它,因此类型错误。

如果您来自弱类型语言(例如具有隐式类型强制的javascript),则此行为可能会令人惊讶。

答案 1 :(得分:1)

所以让我们把它分开一点。一,原始功能:

flip (\n s -> show n <> s) "Ten" 10

如果我们采用每个部分的类型,我们会看到什么?

> :t flip
forall a b c. (a -> b -> c) -> b -> a -> c

当然这实际上只是flip,它需要一个双参数函数并将其转换为另一个参数翻转。

接下来,这是有趣的部分,(a -> b -> c)的{​​{1}},它变为flip

b -> a -> c

好的,那么,> :t (\n s -> show n <> s) forall t4. Show t4 => t4 -> String -> String 是如何产生的呢?此引用t4 -> String -> String的唯一功能是String

show

此外,这是> :t show forall a. Show a => a -> String 上的Show约束来自的地方。 PureScript告诉我们的是t4是一个函数,它需要两个参数,并返回(\n s -> show n <> s)

它正在调用我们的第一个参数String,它是此会话的有效且唯一的类型变量。它也无法告诉我们t4的任何内容,但由于t4需要show的实例,Show必须是t4的实例。

现在,在我们的Show上调用show将返回Show => t4,我们希望String能够这样做:

show

(是的,我们已经看过了。)因此,在我们的函数> :t show forall a. Show a => a -> String 中,(\n s -> show n <> s)字词的类型为show n。这是因为String已完全应用show,这是t4的一个实例,因此编译器可以推断出Show的类型为{{1} },show n

现在这是它变得有趣的地方。 show最常见的形式有一个类型参数:

String

这是一个函数,它需要两个<>类型的值,并返回一个类型为> :t (<>) forall a. Semigroup a => a -> a -> a 的新值。请注意,虽然函数具有类型参数,但它只有一个类型参数,因此任何特定的a在其类型中都不会是多态的。

现在,虽然我们的函数在其第一个参数中是多态的,但它也只有一个类型变量。这实际上有点像红鲱鱼,因为让我们看看a做了什么:

(<>)

哇。我们的多态参数仍然存在,但现在它是第二个。这就是flip的作用。那是什么意思呢,真的吗?

> :t flip (\n s -> show n <> s)
forall t5. Show t5 => String -> t5 -> String

在这种情况下,flip> flip (\n s -> show n <> s) "Ten" 10 ,我们的"Ten" ped函数需要它。 String就是这样:

flip

在这种情况下,它是10> :t 10 Int Int的实例吗?

Int

是的!因此,值Show> show (10 :: Int) "10" 满足"Ten" ped函数10的参数,其中flipforall a. Show a => String -> a -> String和{{1 {},"Ten"String的实例。

现在,让我们看一下失败的案例:

10

IntShow> flip (\n s -> show n <> s) 10 "Ten" "Ten"的实例吗?

String

是的!整齐!所以没关系。现在,Stringshow吗?嗯,不,可悲的是,事实并非如此。因此> show "Ten" "\"Ten\"" 不能用作10 ped函数的第一个参数。