将通用类型变量统一为另一个现有类型

时间:2018-10-07 14:39:36

标签: type-inference elm

下面的line中有一个Elm guide

Task.perform AdjustTimeZone Time.here

我发现了以下类型签名:

-- ∵
AdjustTimeZone :  Zone -> Msg
here           :                  Task x     Zone
perform        : (a    -> msg) -> Task Never a    -> Cmd msg 
-- ∴
perform AdjustTimeZone here :                        Cmd Msg

如何将Task x Zone统一为Task Never a?特别是,xNever值得怀疑,而Zonea则合理。

1 个答案:

答案 0 :(得分:3)

我不是类型推断专家,但我认为说“ {x统一为Never”并不正确,并怀疑这是您困惑的根源。 xa都是类型变量,除非有其他约束发生冲突,否则它们将统一使用这两种方式。因此,就像a变成Zone一样,x变成Never,而不是相反。

您可能还想知道为什么Time.here的类型为Task x Zone而不是Task Never Zone,因为毕竟here应该知道它是否会出错。我认为这是因为1)无关紧要(对于类型系统,尽管它当然对用户来说可能),2)它使其更易于组合。

因此,假设您想将Time.here与其他可能发生错误的其他Task进行排序。 Task.andThen具有类型(a -> Task x b) -> Task x a -> Task x b,其中x(错误)类型变量在所有Task中都相同。因此,如果Time.here的类型为Task Never Zone,则我们必须为andThen提供函数Zone -> Task Never b。那显然是行不通的。

我非常确定您可以执行TasK.here |> Task.mapError never |> Task.andThen (\zone -> ...),但是如果错误类型留为类型变量而不是被约束为Never,则这并不是必须的。这不是问题,因为Task.here不会产生任何x,因此它统一为什么都没有关系。