简体   繁体   English

在函数中键入同义词展开?

[英]Type synonyms unwrapping in functions?

Reading book by Simon Marlow " Parallel and Concurrent Programming in Haskell " I encountered a thing I am not sure about why it works the way GHC sees it. Simon Marlow的阅读书“ Haskell中的并行和并发编程 ”我遇到了一个我不确定它为什么会像GHC看到的那样工作的东西。 Namely: 即:

evalPair :: Strategy a -> Strategy b -> Strategy (a,b)
evalPair sa sb (a,b) = do
  a' <- sa a
  b' <- sb b
  return (a',b')

Has two input arguments (the way I see it Strategy a and Strategy b ) on type level and one output - Strategy (a,b) . 在类型级别和一个输出上有两个输入参数(我将其Strategy aStrategy b ) - Strategy (a,b) But line under there are three arguments: sa , sb and (a,b) . 但是下面的行有三个参数: sasb(a,b) It is confusing. 这令人困惑。

But since Strategy is type synonym: 但由于Strategy是类型同义词:

type Strategy a = a -> Eval a

I thought that maybe if I unroll Strategies to (a -> Eval a) it will be clearer. 我想也许如果我将策略展开(a - > Eval a)它会更清楚。 So: 所以:

evalPair :: (a -> Eval a) -> (b -> Eval b) -> (a,b) -> Eval (a,b)

and (brackets added on the end) 和(括号末尾添加)

evalPair :: (a -> Eval a) -> (b -> Eval b) -> ((a,b) -> Eval (a,b))

both compile. 都编译。

Then I wrote it this way and thanks to Stack tooltips found that what is returned from function evalPair (went back to Strategy on purpose to make it more confusing) is not Strategy (a,b) but Eval (a,b) . 然后我用这种方式编写它并且感谢Stack工具提示发现从函数evalPair返回的内容(故意回到策略以使其更加混乱)不是Strategy (a,b)而是Eval (a,b)

evalPair :: Strategy a -> Strategy b -> Strategy (a,b)
evalPair sa sb (a,b) = 
let res = do
          a' <- sa a
          b' <- sb b
          return (a', b')
in res

So clearly compiler unwrapped last argument from its type synonym, but only the last one - since we do not need to provide values for Strategy a and Strategy b 很明显,编译器从其类型同义词中解开了最后一个参数,但只是最后一个 - 因为我们不需要为Strategy aStrategy b提供值

Here are my questions: 这是我的问题:

  1. Where can I get more information on this behaviour of the compiler? 在哪里可以获得有关编译器此行为的更多信息? Why the function returns Eval a even though it says that it returns Strategy a 为什么函数返回Eval a即使它表示它返回Strategy a

  2. If unwrapping happens, then why don't I need (and can't in fact) provide values for Strategy a and Strategy b like so: 如果解缠发生,那么为什么我不需要(实际上不能)为Strategy aStrategy b提供这样的值:

     evalPair :: Strategy a -> Strategy b -> Strategy (a,b) evalPair a sa a sb (a,b) = do a' <- sa a b' <- sb b return (a',b') 

Given the type synonym 给定类型同义词

type Strategy a = a -> Eval a

And the type 和类型

Strategy a -> Strategy b -> Strategy (a,b)

We can "desugar" the type by replacing each use of the synonym with its definition: 我们可以通过将同义词的每次使用替换为其定义来“desugar”类型:

(a -> Eval a) -> (b -> Eval b) -> ((a,b) -> Eval (a,b))

Note that the parens are necessary here to clarify what's going on. 请注意,这里必须使用parens来澄清发生了什么。 The function evalPair still takes two arguments. 函数evalPair仍然有两个参数。 Its two arguments are two functions . 它的两个参数是两个函数 This may be clearer if I visually align the types with their corresponding arguments like so: 如果我在视觉上将类型与相应的参数对齐,可能会更清楚:

evalPair :: (a -> Eval a) -> (b -> Eval b) -> (a,b) -> Eval (a,b)
evalPair    sa               sb               (a,b)  = ...

Therefore the type of sa is a -> Eval a , and the type of sb is b -> Eval b . 因此sa的类型是a -> Eval asb的类型是b -> Eval b

Note that the Haskell Report states: 请注意,Haskell报告指出:

Type synonyms are a convenient, but strictly syntactic, mechanism to make type signatures more readable. 类型同义词是一种方便但严格的语法机制,可使类型签名更具可读性。 A synonym and its definition are completely interchangeable 同义词及其定义完全可以互换

Therefore, the compiler may freely "wrap" or "unwrap" type synonyms, as they are "completely interchangeable". 因此,编译器可以自由地“包装”或“展开”类型同义词,因为它们是“完全可互换的”。

You can read about Type Synonyms in the Haskell Report, section 4.2.2: https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-730004.2.2 您可以在Haskell报告的4.2.2节中阅读有关类型同义词的内容: https//www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-730004.2.2

You are misunderstanding how Haskell functions work. 您误解了Haskell函数的工作原理。

All Haskell functions have only one argument . 所有Haskell函数只有一个参数 If a function f takes a value of type A , and returns something of type B , we write f :: A -> B . 如果函数f采用类型A的值,并返回类型B东西,我们写f :: A -> B

However, of course, we can write functions with multiple arguments, but in a clever way, called currying . 但是,当然,我们可以用多个参数编写函数,但是以一种聪明的方式,称为currying If we want a function g that takes an A and a B , and produces a C , we actually write a function that takes an A , and then returns a function that takes a B and returns a C . 如果我们想要一个带有AB的函数g ,并产生一个C ,我们实际上写一个带A的函数,然后返回一个带B的函数并返回一个C

We write this as g :: A -> (B -> C) . 我们把它写成g :: A -> (B -> C) However, since this is what we usually want to do with functions, the Haskell compiler will read the signature g :: A -> B -> C as the same thing. 但是,由于这是我们通常想要的函数,Haskell编译器将读取签名g :: A -> B -> C作为相同的东西。

This means that when we write A -> B -> C -> ... -> Z , we really mean A -> (B -> (C -> (... -> Z...))) . 这意味着当我们写A -> B -> C -> ... -> Z ,我们的意思是A -> (B -> (C -> (... -> Z...)))

However, if we write g :: (A -> B) -> C , this is not the same thing! 但是,如果我们写g :: (A -> B) -> C这不是一回事! Brackets matter! 括号很重要! g is now a function that takes a function and produces a C . g现在是一个函数,它接受一个函数并产生一个C

Now, let's inspect this specific example: 现在,让我们检查一下这个具体的例子:

 evalPair :: (a -> Eval a) -> (b -> Eval b) -> (a,b) -> Eval (a,b)

I read this as: 我读到这个:

The function evalPair takes the following: evalPair函数采用以下方法:

  • Something of type a -> Eval a 类型a -> Eval a
  • Something of type b -> Eval b 类型为b -> Eval b东西b -> Eval b
  • Something of type (a,b) 某种类型(a,b)

And produces something of type Eval (a,b) . 并产生Eval (a,b)类型的东西。

So the declaration would naturally look something like 所以声明自然会像

evalPair first_arg second_arg third_arg = -- ...

Writing evalPair a sa a sb (a,b) = -- ... is nonsensical, since that takes 5 arguments, and thus evalPair would have a type of the form a -> b -> c -> (d, e) -> f , which is completely different to what we expect. evalPair a sa a sb (a,b) = -- ...是荒谬的,因为它需要5个参数,因此evalPair将有一个类型的形式a -> b -> c -> (d, e) -> f ,这与我们的期望完全不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM