f# - 为什么有些 FAKE 方法在目标函数中不起作用?

标签 f# target f#-fake

考虑以下因素:

#r @"FakeLib.dll"

open Fake
open Fake.StringHelper
open Fake.ProcessHelper

Shell.Exec("mkdir","exampleDirectory")

Target "DoStuff" ( fun () -> 
    trace "Doing Stuff..."
)

Target "Clean" ( fun () -> 
    trace  "Cleaning..."
)

Target "Deploy" (fun () -> 
    trace  "Deploying..."
)

"DoStuff"
    ==>"Clean"
    ==>"Deploy"

RunTargetOrDefault "Deploy"

上面的脚本工作正常,但是当我像这样在目标中移动 Shell.Exec 时:

#r @"FakeLib.dll"

open Fake
open Fake.StringHelper
open Fake.ProcessHelper

Target "DoStuff" ( fun () -> 
    trace "Doing Stuff..."
    Shell.Exec("mkdir","exampleDirectory")
)

Target "Clean" ( fun () -> 
    trace  "Cleaning..."
)

Target "Deploy" (fun () -> 
    trace  "Deploying..."
)

"DoStuff"
    ==>"Clean"
    ==>"Deploy"

RunTargetOrDefault "Deploy"

我最终遇到了一个错误:

FsiEvaluationException:

Error:

        DeployScript.fsx(10,5): error FS0001: This expression was expected to have type
            unit
        but here has type
            int


Output: [Loading C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx]


Input: C:\Users\myusername\Desktop\SomeFolder\DeployScript.fsx
\Arguments:
  C:\fsi.exe

Exception: Yaaf.FSharp.Scripting.FsiEvaluationException: Error while compiling or executing fsharp snippet. ---> System.Exception: Operation failed. The error text has been print the error stream. To return the corresponding FSharpErrorInfo use the EvalInteractionNonThrowing, EvalScriptNonThrowing or EvalExpressionNonThrowing
   at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.commitResult[a,b](FSharpChoice`2 res)
   at Microsoft.FSharp.Compiler.Interactive.Shell.FsiEvaluationSession.EvalScript(String filePath)
   at Yaaf.FSharp.Scripting.Helper.evalScript@1303.Invoke(String arg00) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1303
   at Yaaf.FSharp.Scripting.Helper.save_@1276-2.Invoke(Unit unitVar0) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1277
   at Yaaf.FSharp.Scripting.Helper.consoleCapture[a](TextWriter out, TextWriter err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1221
   at Yaaf.FSharp.Scripting.Helper.redirectOut@1247[a](Boolean preventStdOut, OutStreamHelper out, OutStreamHelper err, FSharpFunc`2 f) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1254
   at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1276
   --- End of inner exception stack trace ---
   at Yaaf.FSharp.Scripting.Helper.save_@1275-1.Invoke(String text) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1284
   at Yaaf.FSharp.Scripting.Helper.session@1306.Yaaf-FSharp-Scripting-IFsiSession-EvalScriptWithOutput(String ) in C:\code\fake\paket-files\matthid\Yaaf.FSharp.Scripting\src\source\Yaaf.FSharp.Scripting\YaafFSharpScripting.fs:line 1308
   at Fake.FSIHelper.runScriptUncached(Boolean useCache, String scriptPath, IEnumerable`1 fsiOptions, Boolean printDetails, CacheInfo cacheInfo, TextWriter out, TextWriter err) in C:\code\fake\src\app\FakeLib\FSIHelper.fs:line 471
DeployScript.fsx(10,5): error FS0001: This expression was expected to have type

这里的要点是我试图仅在特定目标下执行 shell 命令。不要注意 mkdir 命令,因为我实际上想使用 schtasks 命令。为了简单起见,我只是使用 mkdir 。也许我在这里遗漏了一个细微差别。我还注意到使用 environVarOrFail 时也会出现同样的行为。预先感谢所有回复的人。

最佳答案

Shell.Exec 返回一个 int,但 Target 需要一个返回 unit 的函数。

试试这个:

let returnUnit() = ()
let return42() = 42

Target "One" returnUnit // works
Target "Two" return42 // fails: expected to have type unit, but here has type int

目标“Two”无法编译,因为它的第二个参数是一个返回 int 的函数,而预期是返回 unit 的函数。

此错误是为了防止您忘记函数返回值:编译器会帮助您告诉您“嘿,您确定不想对这个 int 执行任何操作吗?那么您为什么首先调用该函数?”

然而,有时丢弃返回值是有意义的。例如,在这种特殊情况下,您调用 Shell.Exec 是因为它的副作用,而您对它的返回值不感兴趣。这种情况发生得非常频繁,以至于有一个特殊的函数可以应对它 - ignore

Target "DoStuff" ( fun () -> 
    trace "Doing Stuff..."
    Shell.Exec("mkdir","exampleDirectory") |> ignore // compiles fine
)

该函数接受任意值,将其丢弃,然后返回一个单位。通过将其应用于Shell.Exec的结果,您可以告诉编译器:“是的,我确定我不需要这个值,请忽略它。”

<小时/>

也就是说,我强烈建议使用专用函数而不是通用系统调用。这将使您的脚本更具可读性,甚至可以帮助您及早发现偶尔的错误。例如,要创建目录,请使用 FileUtils.mkdir:

Target "DoStuff" ( fun () -> 
    trace "Doing Stuff..."
    FileUtils.mkdir "exampleDirectory"  // no need for `ignore`, mkdir already returns `unit`
)

关于f# - 为什么有些 FAKE 方法在目标函数中不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44938613/

相关文章:

c - GNU 使 : different dependencies of several binaries in the same target?

f# - 运算符(operator)</>在FAKE构建脚本中做什么?

haskell - 用于功能并行的编程语言 : F# vs Haskell

html - 仅使用 css 单击另一个图像/元素时隐藏图像?

c# - 对连接丢失使用react

ios - Swift 4 - 设置最低部署目标

f# - 在带括号的项目文件上运行 FAKE MSBUild 时出现构建错误

f#-fake - 确保最新 F# FAKE 的最佳方法?

data-structures - F# 记录是否支持循环引用 A -> B -> A?

compiler-construction - F# 编译器如何/何时提前读取类型推断?