我正在尝试使用https://fsharpforfunandprofit.com/posts/elevated-world-3/ 中的以下代码
它在 Fable 中无法正常工作,但在 dotnet 核心中工作正常。
module AppFunc
open System
let (<!>) = Result.map
let apply fResult xResult =
match fResult,xResult with
| Ok f, Ok x ->
Ok (f x)
| Error errs, Ok x ->
Error errs
| Ok f, Error errs ->
Error errs
| Error errs1, Error errs2 ->
// concat both lists of errors
Error (List.concat [errs1; errs2])
let (<*>) = apply
我正在使用如下所示
let private createLoginInternal username password =
{UserName = username; Password = password }
let createLogin username password =
createLoginInternal <!> (Email.create username) <*> (Password.create password)
类型电子邮件和密码被声明为
type Email = EmailType of string
with
static member create = function
| x when String.IsNullOrEmpty(x) -> Error ["Email must not be empty."]
| x when not (x.Contains("@")) -> Error ["Email must contain '@'."]
| x when not (x.Contains(".")) -> Error ["Email must contain '.'."]
| x -> Ok(EmailType x)
member this.Value =
let _val (EmailType x) =
x
_val this
type Password = PasswordType of string
with
static member create = function
| x when String.IsNullOrEmpty(x) -> Error ["Password must not be empty."]
| x when x.Length < 5 -> Error ["Password must have atleast 5 characters."]
| x -> Ok(PasswordType x)
member this.Value =
let _val (PasswordType x) =
x
_val this
从 Suave 应用程序调用 create login 如下所示工作正常
createLogin "[email protected]" "masterkey"
但 Fable 失败,错误Unable to process a message: TypeError: matchValue[0].data is not a function
使用Option
在 REPL 中无需任何外部依赖即可重现:
open System
let apply f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None
let (<!>) = Option.map
let (<*>) = apply
type Login =
{ Name : Name
Password : Password }
and Name =
| Name of string
static member create = function
| s when not (String.IsNullOrEmpty s) -> Some (Name s)
| _ -> None
and Password =
| Password of string
static member create = function
| s when String.length s >= 5 -> Some (Password s)
| _ -> None
let private createLoginInternal name password =
{ Name = name; Password = password }
let createLogin name password =
createLoginInternal <!> (Name.create name) <*> (Password.create password)
createLogin "jd" "secret"
|> printfn "%A"
但是,通过此更改可以轻松修复:
| _ -> None
-let (<!>) = Option.map
+let (<!>) f x = Option.map f x
let (<*>) = apply
type Login =
@sandeepc24你能尝试这样做吗:
-let (<!>) = Result.map
+let (<!>) f x = Result.map f x
这个示例更紧凑:
let apply f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None
let (<!>) f x = Option.map f x
let (<*>) = apply
let x = (+) <!> Some 40 <*> Some 2
x |> Option.iter (printfn "%i")
要使具有两个以上参数的函数起作用,我们还必须对<*>
执行相同的操作,否则它会失败并出现相同的错误:
let (<!>) f x = Option.map f x
let (<*>) f x = apply f x
let add3 a b c = a + b + c
let x = add3 <!> Some 40 <*> Some 1 <*> Some 1
-let () = 结果.map
+let () fx = 结果.map fx
这有效,谢谢 inosik
非常感谢@inosik 的帮助! 是的,无点风格有时会混淆寓言。 很高兴你让它在@sandeepc24工作,但我会尝试检查它是否可以被修复。 感谢报告:)
使用最新的开发版本let (<*>) = apply
也可以工作,所以也许问题只是解决了 :smile: 虽然在使用无点免费版本 ( let (<*>) f x = apply f x
) 时生成的 JS 代码要好得多,所以我d 建议使用那个:+1:
我暂时关闭这个问题,如果你发现类似的问题,请告诉我。
使用最新的开发版本 let (<*>) = apply 也可以使用
我只是做了一个完整的构建,然后是.\build.cmd QuickFableCompilerTest
,它不适用于无点<!>
或<*>
。 我将此添加到QuickTest.fs
:
let apply f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None
let add3 a b c = a + b + c
module PointFree =
let (<!>) = Option.map
let (<*>) = apply
let x = add3 <!> Some 40 <*> Some 1 <*> Some 1
module Pointful =
let (<!>) f x = Option.map f x
let (<*>) f x = apply f x
let x = add3 <!> Some 40 <*> Some 1 <*> Some 1
let ``My Test``() =
equal PointFree.x Pointful.x
它仍然崩溃:
D:\projects\fable\src\tools\temp\QuickTest.js:1503
return new Some($var1[1]($var1[2]));
^
TypeError: $var1[1] is not a function
at apply (D:\projects\fable\src\tools\temp\QuickTest.js:1503:37)
at D:\projects\fable\src\tools\temp\QuickTest.js:1521:20
at curriedFn (D:\projects\fable\src\tools\temp\QuickTest.js:1466:25)
at D:\projects\fable\src\tools\temp\QuickTest.js:1525:78
at Object.<anonymous> (D:\projects\fable\src\tools\temp\QuickTest.js:1529:2)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
嗯,你说得对。 这仍然是一个问题。 非常感谢您的新测试,我会尝试修复它! :+1:
@alfonsogarciacaro这是使用 3 个参数吗?
您计划何时发布此修复程序,因为我需要它继续我的开发?
我花了更多时间研究这个问题,但仍然收到此错误。 这是我的代码。 当我调用 createUser 时,我得到同样的错误。
module Domain.StringTypes
open System
let private applyValidations value okFun errorFun validations =
let validationResults = validations
|> List.fold(fun a (f,m) -> if f value then m :: a else a) []
|> List.rev // Reverse the list as error messages are added as head element to the list.
if List.isEmpty validationResults then
okFun
else
errorFun validationResults
type String150 =
String150Type of string
with
static member create = function
| x when String.length(x) <= 150 -> Ok(String150Type x)
| _ -> Error(["Length cannot be more than 150."])
static member CreateNonBlank stringTitle = function
| x when (String.length(x) > 0 && String.length(x) <= 150) -> Ok(String150Type x)
| _ ->
let title = if String.IsNullOrEmpty stringTitle then "String" else stringTitle
Error([title + " cannot be blank and must be less than 150."])
member this.Value =
let _val (String150Type x) =
x
_val this
type Email = EmailType of string
with
static member Create (title, email) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
((fun x -> not (x.Contains("@"))), title + " must contain '@'.")
((fun x -> not (x.Contains("."))), title + " must contain '.'.")
]
|> applyValidations email (Ok (EmailType email)) Error
static member Create email =
Email.Create ("Email", email)
member this.Value =
let _val (EmailType x) =
x
_val this
type Password = PasswordType of string
with
static member Create (title, password) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations password (Ok (PasswordType password)) Error
static member Create password =
Password.Create ("Password", password)
member this.Value =
let _val (PasswordType x) =
x
_val this
type FirstName = FirstNameType of string
with
static member Create (title, firstName) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
//((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations firstName (Ok (FirstNameType firstName)) Error
static member Create firstName =
FirstName.Create ("FirstName", firstName)
member this.Value =
let _val (FirstNameType x) =
x
_val this
type LastName = LastNameType of string
with
static member Create (title, lastName) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
//((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations lastName (Ok (LastNameType lastName)) Error
static member Create lastName =
LastName.Create ("LastName", lastName)
member this.Value =
let _val (LastNameType x) =
x
_val this
type ContactName = ContactNameType of string
with
static member Create (title, contactName) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
//((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations contactName (Ok (ContactNameType contactName)) Error
static member Create contactName =
ContactName.Create ("ContactName", contactName)
member this.Value =
let _val (ContactNameType x) =
x
_val this
type Website = WebsiteType of string
with
static member Create (title, website) =
match website with
| Some website ->
[
// If website is not blank then it must start with http in it.
((fun (x : string) -> (x.Length > 0 && not (x.ToLower().StartsWith("http")))), title + " must have http.")
]
|> applyValidations website (Ok (Some (WebsiteType website))) Error
| None -> Ok None
static member Create website =
Website.Create ("Website", website)
member this.Value =
let _val (WebsiteType x) =
x
_val this
type Phone = PhoneType of string
with
static member Create (title, phone) =
match phone with
| Some phone ->
[
// If phone is not blank then it must have atleast 4 digits.
((fun (x : string) -> x.Length > 0 && x.Length < 5), title + " must have at least 4 digits.")
]
|> applyValidations phone (Ok (Some (PhoneType phone))) Error
| None -> Ok None
static member Create phone =
Phone.Create ("Phone", phone)
member this.Value =
let _val (PhoneType x) =
x
_val this
type Mobile = MobileType of string
with
static member Create (title, mobile) =
match mobile with
| Some mobile ->
[
// If phone is not blank then it must have atleast 4 digits.
((fun (x : string) -> x.Length > 0 && x.Length < 5), title + " must have at least 4 digits.")
]
|> applyValidations mobile (Ok (Some (MobileType mobile))) Error
| None -> Ok None
static member Create mobile =
Mobile.Create ("Mobile", mobile)
member this.Value =
let _val (MobileType x) =
x
_val this
type Fax = FaxType of string
with
static member Create (title, fax) =
match fax with
| Some fax ->
[
// If phone is not blank then it must have atleast 4 digits.
((fun (x : string) -> x.Length > 0 && x.Length < 5), title + " must have at least 4 digits.")
]
|> applyValidations fax (Ok (Some (FaxType fax))) Error
| None -> Ok None
static member Create fax =
Fax.Create ("Fax", fax)
member this.Value =
let _val (FaxType x) =
x
_val this
`
Here is the UserDto declaration.
`
type UserDto = {
FirstName : FirstName
LastName : LastName
ContactName : ContactName
Email : Email
Website : Website option
Phone : Phone option
Mobile : Mobile option
Fax : Fax option
}
let private createUserInternal firstName lastName contactName email website phone mobile fax =
{
FirstName = firstName
LastName = lastName
ContactName = contactName
Email = email
Website = website
Phone = phone
Mobile = mobile
Fax = fax
}
let createUser firstName lastName contactName email website phone mobile fax =
createUserInternal <!> FirstName.Create firstName
<*> LastName.Create lastName
<*> ContactName.Create contactName
<*> Email.Create email
<*> Website.Create website
<*> Phone.Create phone
<*> Mobile.Create mobile
<*> Fax.Create fax
有关信息, @sandeepc24似乎没有更新到 Fable 的测试版,所以他没有在本地安装修复程序。 我们应该等待确认该错误仍然存在或不存在,但使用最新的 Fable 测试版。
马克西姆·曼格尔
@sandeepc24你升级到最新的寓言测试版了吗?
桑迪普·钱德拉
还没有,我该怎么做?
@sandeepc24抱歉,我想我在测试版中添加了修复程序,但这仍然存在一些其他问题。 让我在发布新版本之前修复它们。 之后,您只需在paket.dependencies
添加prelease
即可升级它,例如:
clitool dotnet-fable prerelease
nuget Fable.Core prerelease
然后运行mono .paket/paket.exe update
和dotnet restore
。 或者,您能否在@inosik示例中添加一个测试
@alfonsogarciacaro - 很抱歉打扰您,但我想知道这是否已解决?
我想知道同样的 ;) 你检查过最新版本吗?
我更新到 1.3,但问题仍然存在:-(
这是我的 paket.lock 文件的图像。
@sandeepc24您能否尝试在没有依赖关系的较小代码中隔离问题? 此注释中的代码很长,并且不是通过将其粘贴到文件中来编译的。 此外,如果未提供预期结果,则很难从中创建测试以确保该问题不会在未来版本中再次出现。
这是一个文件中的代码
#r "node_modules/fable-core/Fable.Core.dll"
open System
open System.Threading
open Fable.Core
open Fable.Import.Browser
let (<!>) = Result.map
let apply fResult xResult =
match fResult,xResult with
| Ok f, Ok x ->
Ok (f x)
| Error errs, Ok x ->
Error errs
| Ok f, Error errs ->
Error errs
| Error errs1, Error errs2 ->
// concat both lists of errors
Error (List.concat [errs1; errs2])
let (<*>) f x = apply f x
let private applyValidations value okFun errorFun validations =
let validationResults = validations
|> List.fold(fun a (f,m) -> if f value then m :: a else a) []
|> List.rev // Reverse the list as error messages are added as head element to the list.
if List.isEmpty validationResults then
okFun
else
errorFun validationResults
type String150 =
String150Type of string
with
static member create = function
| x when String.length(x) <= 150 -> Ok(String150Type x)
| _ -> Error(["Length cannot be more than 150."])
static member CreateNonBlank stringTitle = function
| x when (String.length(x) > 0 && String.length(x) <= 150) -> Ok(String150Type x)
| _ ->
let title = if String.IsNullOrEmpty stringTitle then "String" else stringTitle
Error([title + " cannot be blank and must be less than 150."])
member this.Value =
let _val (String150Type x) =
x
_val this
type Email = EmailType of string
with
static member Create (title, email) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
((fun x -> not (x.Contains("@"))), title + " must contain '@'.")
((fun x -> not (x.Contains("."))), title + " must contain '.'.")
]
|> applyValidations email (Ok (EmailType email)) Error
static member Create email =
Email.Create ("Email", email)
member this.Value =
let _val (EmailType x) =
x
_val this
type Password = PasswordType of string
with
static member Create (title, password) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations password (Ok (PasswordType password)) Error
static member Create password =
Password.Create ("Password", password)
member this.Value =
let _val (PasswordType x) =
x
_val this
type FirstName = FirstNameType of string
with
static member Create (title, firstName) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
//((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations firstName (Ok (FirstNameType firstName)) Error
static member Create firstName =
FirstName.Create ("FirstName", firstName)
member this.Value =
let _val (FirstNameType x) =
x
_val this
type LastName = LastNameType of string
with
static member Create (title, lastName) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
//((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations lastName (Ok (LastNameType lastName)) Error
static member Create lastName =
LastName.Create ("LastName", lastName)
member this.Value =
let _val (LastNameType x) =
x
_val this
type ContactName = ContactNameType of string
with
static member Create (title, contactName) =
[
(String.IsNullOrEmpty, title + " must not be empty.")
//((fun x -> x.Length < 5), title + " must have atleast 5 characters.")
]
|> applyValidations contactName (Ok (ContactNameType contactName)) Error
static member Create contactName =
ContactName.Create ("ContactName", contactName)
member this.Value =
let _val (ContactNameType x) =
x
_val this
type Website = WebsiteType of string
with
static member Create (title, website) =
match website with
| Some website ->
[
// If website is not blank then it must start with http in it.
((fun (x : string) -> (x.Length > 0 && not (x.ToLower().StartsWith("http")))), title + " must have http.")
]
|> applyValidations website (Ok (Some (WebsiteType website))) Error
| None -> Ok None
static member Create website =
Website.Create ("Website", website)
member this.Value =
let _val (WebsiteType x) =
x
_val this
type Phone = PhoneType of string
with
static member Create (title, phone) =
match phone with
| Some phone ->
[
// If phone is not blank then it must have atleast 4 digits.
((fun (x : string) -> x.Length > 0 && x.Length < 5), title + " must have at least 4 digits.")
]
|> applyValidations phone (Ok (Some (PhoneType phone))) Error
| None -> Ok None
static member Create phone =
Phone.Create ("Phone", phone)
member this.Value =
let _val (PhoneType x) =
x
_val this
type Mobile = MobileType of string
with
static member Create (title, mobile) =
match mobile with
| Some mobile ->
[
// If phone is not blank then it must have atleast 4 digits.
((fun (x : string) -> x.Length > 0 && x.Length < 5), title + " must have at least 4 digits.")
]
|> applyValidations mobile (Ok (Some (MobileType mobile))) Error
| None -> Ok None
static member Create mobile =
Mobile.Create ("Mobile", mobile)
member this.Value =
let _val (MobileType x) =
x
_val this
type Fax = FaxType of string
with
static member Create (title, fax) =
match fax with
| Some fax ->
[
// If phone is not blank then it must have atleast 4 digits.
((fun (x : string) -> x.Length > 0 && x.Length < 5), title + " must have at least 4 digits.")
]
|> applyValidations fax (Ok (Some (FaxType fax))) Error
| None -> Ok None
static member Create fax =
Fax.Create ("Fax", fax)
member this.Value =
let _val (FaxType x) =
x
_val this
type UserDto = {
FirstName : FirstName
LastName : LastName
ContactName : ContactName
Email : Email
Website : Website option
Phone : Phone option
Mobile : Mobile option
Fax : Fax option
}
let private createUserInternal firstName lastName contactName email website phone mobile fax =
{
FirstName = firstName
LastName = lastName
ContactName = contactName
Email = email
Website = website
Phone = phone
Mobile = mobile
Fax = fax
}
let createUser firstName lastName contactName email website phone mobile fax =
createUserInternal <!> FirstName.Create firstName
<*> LastName.Create lastName
<*> ContactName.Create contactName
<*> Email.Create email
<*> Website.Create website
<*> Phone.Create phone
<*> Mobile.Create mobile
<*> Fax.Create fax
createUser "Sandeep" "Chandra" "Sandeep" "[email protected]" None None None None
输出应该是
Ok {FirstName = FirstNameType "Sandeep";
LastName = LastNameType "Chandra";
ContactName = ContactNameType "Sandeep";
Email = EmailType "[email protected]";
Website = None;
Phone = None;
Mobile = None;
Fax = None;}
我无法使用 Fable 1.3.0 重现它,使用 Webpack 和 Rollup 作为捆绑器,并编译为 Node 应用程序。 它也适用于 REPL。
我还尝试将 apply 运算符更改为无点样式,这也有效。
@sandeepc24您的 JS 依赖项是最新的吗?
将<!>
运算符更改为有针对性的样式 ( let (<!>) f x = Result.map f x
) 使其中断。
再次简化为:
let apply f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None
let (<!>) mapping option = Option.map mapping option
//let (<!>) = Option.map
let (<*>) f x = apply f x
//let (<*>) = apply
let add3 a b c = a + b + c
let sum = add3 <!> Some 1 <*> Some 2 <*> Some 3
printfn "%A" sum
| <!>
| <*>
| 结果 |
|------------|------------|--------|
| 点免费 | 点免费 | 好的 |
| 有意义的| 点免费 | 错误 |
| 点免费 | 有意义的| 好的 |
| 有意义的| 有意义的| 好的 |
这就是我们的测试通过的原因。 因为我们要么使用 point free 要么使用 pointful 风格,但没有使用任何排列。
参数的数量会改变结果 :confused:
let add a b = a + b
let add3 a b c = a + b + c
let apply f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None
[<CompiledName("mapOp")>]
let (<!>) mapping option = Option.map mapping option
//let (<!>) = Option.map
[<CompiledName("applyOp")>]
let (<*>) f x = apply f x
//let (<*>) = apply
try
let (Some x) = add <!> Some 1 <*> Some 2
printfn "add: OK (%i)" x
with
| _ -> printfn "add: Error"
try
let (Some x) = add3 <!> Some 1 <*> Some 2 <*> Some 3
printfn "add3: OK (%i)" x
with
| _ -> printfn "add3: Error"
| <!>
| <*>
| 结果add
| 结果add3
|
|------------|------------|--------------|-------- -------|
| 点免费 | 点免费 | 错误 | 好的 |
| 有意义的| 点免费 | 好的 | 错误 |
| 点免费 | 有意义的| 错误 | 好的 |
| 有意义的| 有意义的| 好的 | 好的 |
非常感谢@inosik 为调查问题所做的所有工作! 非常有趣的结果,我会尝试修复它......或者绝对禁止寓言中的点自由风格;)
寓言中禁止点自由风格
那么我们应该怎么做["foo"] |> List.exists ((=) "bar")
呢? :微笑:
在无点情况下,生成的代码似乎错过了一些partialApply
调用。 我将第一种情况(点免费地图和应用)更改为:
try
let add1 = add <!> Some 1
console.log ("add1", add1)
let (Some x) = add1 <*> Some 2
console.log ("add: OK (", x, ")")
with
| _ -> console.log "add: Error"
输出是这样的:
add1 0
add: Error
虽然它实际上应该是这样的:
add1 (...args) => {
// _this = _this || this;
const actualArgsLength = Math.max(args.length, 1);
expectedArgsLength = Math.max(expectedArgsLength || f.length, 1);
if (actualArgsLength >= expectedArgsLength) {
const restArgs = args.splice(expectedArgsLength);
const res = f(...args);
if (typeof res === "function") {
const newLambda = CurriedLambda(res);
return restArgs.length === 0 ? newLambda : newLambda(...restArgs);
}
else {
return res;
}
}
else {
return CurriedLambda((...args2) => {
return f(...args.concat(args2));
}, expectedArgsLength - actualArgsLength);
}
}
add: OK ( 3 )
抱歉,我的意思是函数声明中的无点样式。 在我们进一步调查之前,我添加了一条警告,建议用户明确声明所有参数。 我希望这暂时没问题:)
我已更新到最新版本的寓言 (1.3.2),但仍然存在此问题。
这是正常的点自由样式尚不支持。
在 1.3.1 中我们添加了一个警告,但是在不同的项目中它被提出太多,所以我们在 1.3.2 中删除了它。
请明确声明您的所有参数,它应该可以工作。
我不确定如何为我提供的测试用例执行此操作,您能否举一个用于 createUserInternal 的示例?
@sandeepc24将您的运算符更改为有针对性的样式,例如: let (<!>) f x = Result.map f x
。
我们能否检测到用户简单地给函数“别名”的情况? 我认为在这种情况下不需要CurriedLambda
包装,对吗?
@inosik我认为可以检测以无点样式声明的成员并将它们转换为正常方法。 但主要问题是调用站点,其中 F# 编译器提供的 AST 在一种情况下非常不同。 检查以下示例的 F#(不是 Fable)AST 在无点(左)和有点(右)样式之间的差异。 不幸的是,我试图检测这些情况并解决所有情况(如部分应用等)都没有成功😞
我正在努力将警告限制在有问题的情况下,我想我几乎已经做到了。 这可能是目前唯一的解决方案。
@inosik我已经尝试过了,但是对于我有超过 3 个参数的情况,它也失败了。
@alfonsogarciacaro该屏幕截图显示了呼叫站点,我的意思是声明:
let add a b = a + b
let sumOf = add
我们可以检测到sumOf
是add
的别名吗? 然后我们可以生成这样的东西:
function add(a, b) { return a + b; }
var sumOf = add;
另外, @sandeepc24是对的,即使是有针对性的风格也不适用于所有情况。 以下代码段因“thenAdd2 不是函数”而失败:
let apply f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None
[<CompiledName("op_map")>]
let (<!>) f x = Option.map f x
[<CompiledName("op_apply")>]
let (<*>) f x = apply f x
let add a b c d = a+b+c+d
try
let add1 = add <!> Some 1
let thenAdd2 = add1 <*> Some 2
let thenAdd3 = thenAdd2 <*> Some 3
let sum = thenAdd3 <*> Some 4
printfn "%A" sum
with
| e -> printfn "%s" e.Message
也许 JS 根本无法将函数作为一等值使用? :微笑:
啊,好的,现在我明白了。
但是,我认为这里的真正问题实际上并不是点自由样式,因为我上面评论中的代码也不起作用,而以下代码运行得非常好:
let add a b c d = a + b + c + d
let apply f x = f x
let ($) = apply
try
let sum = add $ 1 $ 2 $ 3 $ 4
console.log ("OK:", sum)
with
| e -> console.log ("Error:", e.Message)
如果函数被包装在另一种类型中,部分应用程序似乎有些损坏: @sandeepc24的原始片段中的Result
和再现样本中的Option
。 我也可以用自定义的Maybe<'a>
类型重现它。
@inosik啊,好吧,我错过了。 感谢您指出:+1:这实际上是一个不同的问题(用Some
包装函数)它应该通过这个提交来修复。
好的,这使它适用于Option
:+1: 但这不适用于其他类型,这仍然可以使用自定义类型( type Maybe<'a> = Just of 'a | Nothing
)和可能的Result
重现
@inosik结果也应该有效,因为根据@alfonsogarciacaro这修复了我对这个项目的失败测试: https :
@MangelMaxime当参数超过 2 个时,这似乎会中断:
| add
函数 | 呼叫站点 | 结果 |
|---|---|---|
| let add a b = a+b
| let sum = add <!> Ok 1 <*> Ok 2
| Ok 3
|
| let add a b c = a+b+c
| let sum = add <!> Ok 1 <*> Ok 2 <*> Ok 3
| 错误 |
使它中断的参数数量对我来说看起来很随机,因为它已经使用了Option
3 个参数。 我还不认识这里的模式 :smile:
为了完整起见,这是我添加到QuickTest.fs
:
let apply (f : Result<_, unit>) (x : Result<_, unit>) =
match f, x with
| Ok f, Ok x -> Ok (f x)
| _ -> Result.Error ()
let (<!>) f x = Result.map f x
let (<*>) f x = apply f x
let add a b c = a+b+c
[<Test>]
let Test () =
let sum = add <!> Ok 1 <*> Ok 2 <*> Ok 3
equal (Ok 6) sum
Test ()
好吧,这太疯狂了。 当我将上面代码中的运算符更改为指向自由样式时,它可以工作。 6 个参数和计数。 :厌倦:
@inosik ...这变成了寓言中的测试 1400! 好的,我再次尝试修复应用程序,我希望这次需要更长的时间,直到您发现另一个失败的测试:wink:
谢谢@alfonsogarciacaro ,我可以通过下载 Fable 的测试版来测试它吗?
我更新到 Fable 1.3.3,但上面的 createUser 函数仍然存在问题。
@sandeepc24该修复程序尚未发布。 但是我认为在 Fable 1.3.3 中,如果您将两个运算符更改为指向自由样式( let (<!>) = Result.map
),它应该可以工作。 如果没有,您将不得不等待下一个版本或自己构建 Fable。
@sandeepc24 Fable 1.3.4 已经发布,希望这最终解决了这个问题:)
我已经对此进行了测试,现在对我有用。 非常感谢你们,非常感谢。
太棒了,非常感谢您的确认!
最有用的评论
使用
Option
在 REPL 中无需任何外部依赖即可重现:但是,通过此更改可以轻松修复:
@sandeepc24你能尝试这样做吗: