2016-09-15 133 views
3

在与Idris打交道后,我已经成为使用明确类型的巨大粉丝,通过更频繁地在我的函数中明确写入类型并使用类型别名来加强我的F#程序的声明性自我文档。为什么F#有两种类型的显式类型声明?

定义我的功能与显式类型让我(重新)发现F#实际上有两种功能显式类型的样式。有使用:的标准let函数样式,并且有使用->的lambda函数。

例如

// explicitly typed function using the classical let ':' style 
let OK1 (content : string) (context : Context) : Async<Context option> = 
    { context with Response = { Content = content; StatusCode = 200 } } 
    |> Some 
    |> async.Return 
// explicitly typed function using the '->' style 
let OK2 : string -> Context -> Async<Context option> = fun content context -> 
    { context with Response = { Content = content; StatusCode = 200 } } 
    |> Some 
    |> async.Return 

有关->风格的好处是,我可以定义类型别名,如

// type alias defining a webpart 
type WebPart = Context -> Async<Context option> 
// using the type alias in the declaration of an explicitly typed function 
let OK2 : string -> WebPart = fun content context -> 
    { context with Response = { Content = content; StatusCode = 200 } } 
    |> Some 
    |> async.Return 

我不认为这是可能的声明和使用相同的使用:样式输入别名...?

我很疑惑,为什么F#有两种风格的函数声明显式类型。它是否有某种.Net限制?还是它有一些特殊用途? 为什么不直接用->而不是:定义所有显式类型?

回答

2

我宁可在这里使用术语类型注释而不是“显式类型声明”。后者表明还有比实际更多的东西 - 类型注释仅仅是为了指导编译器(有时甚至是程序员),除此之外别无它物。

这里没有“两种风格”。只有一种风格。你有一个你想要注释的值,你跟着它跟着一个:和类型签名。 ->只是函数类型名称的一部分。

let OK2 : string -> Context -> Async<Context option> = fun content context -> 
    ... 

在上面的片段中,你有一个let结合OK2,你string -> Context -> Async<Context option>类型注释它,你为它提供一个值 - 这恰好是一个函数。对于比较简单的值绑定,这是完全一样的语法:

let simpleValue : int = 42 

但是,这是没有想到的功能的特别方便的方法。而不是价值观,将它们想象成接受一些参数并返回结果的实体会更方便。这就是速记声明捕获的内容。但你似乎alude它不是一个完全不同的,独立的样式,否则这将是不可能的:

let OK2 (content: string): Context -> Async<Context option> = fun context -> 
    ... 

你在说的没错,你不能在这里使用WebPart别名。考虑到您在此处不再具有别名类型的值,这应该不会令人惊讶。

我同意你这样使用函数类型别名是有价值的。它可以让您的功能乍看起来更加统一,这可以提高API的可读性和可发现性 - 但同时,您通过使各个功能的实现更加复杂而付出代价。总是有一个折衷涉及。

1

这两个选项是完全相同的,它们意味着完全相同的东西,以完全相同的方式进行编译。第一个选项是作为一种快捷方式存在的。比较两者:

let f = fun a b -> a + b 
let f a b = a + b 

第二个更短,读起来更容易。

+1

我同意上述案例。虽然这个例子似乎与显式类型无关。我最感兴趣的是为什么显式类型定义在lambda风格和'普通'风格之间不同。在'正常'风格下,你似乎放弃了在显式类型声明中使用类型别名的能力,比如'type WebPart = Context - > Async '。 – Michelrandahl

+1

比较http://stackoverflow.com/questions/39394254/value-restriction-the-type-bar-has-been-inferred-to-have-generic-type。有鉴于此,“两种选择完全相同”的说法可能不成立。不知道,但。 – BitTickler

+0

是的,这个概念确实适用于这种情况。 'foo'是一个常规函数,它的定义相当于'let foo a b = ...',但'bar'是不同的。 –

相关问题