https://fsharpforfunandprofit.com/posts/elevated-world-3/から次のコードを使用しようとしてい
Fableでは正しく機能していません。dotnetcoreでは正常に機能しています。
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)
タイプEメールとパスワードは次のように宣言されています
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アプリからcreateloginを呼び出すと正常に機能します
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")
3つ以上の引数を持つ関数を機能させるには、 <*>
に対しても同じことを行う必要があります。そうしないと、同じエラーで失敗します。
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()= Result.map
+ let()fx = Result.map fx
これはうまくいきました、inosikに感謝します
@inosikを助けてくれてありがとう! はい、ポイントフリースタイルはFableを混乱させることがあります。 @ sandeepc24で動作させたのは良いことですが、とにかく修正できるかどうかを確認します。 レポートのThx :)
最新の開発版ではlet (<*>) = apply
もので、多分問題は、単に固定されて働いている:笑顔を:使用しているときに生成JSコードは非常に良くですがノーポイント・無料版( let (<*>) f x = apply f x
「)Iにそう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の最新ベータ版にアップグレードしましたか?
サンディープチャンドラ
まだ、どうすればそれができますか?
@ 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依存関係のない小さなコードで問題を切り分けてみてください。 このコメントのコードは非常に長く、ファイルに貼り付けてもコンパイルされません。 また、期待される結果が提供されない場合は、問題が将来のバージョンで再発しないことを確認するために、テストを作成することは困難です。
これが1つのファイルのコードです
#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;}
WebpackとRollupの両方をバンドラーとして使用し、Nodeアプリにコンパイルして、Fable1.3.0で再現することはできません。 また、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
| <!>
| <*>
| 結果|
| ------------ | ------------ | -------- |
| ポイントフリー| ポイントフリー| OK |
| ポイント| ポイントフリー| エラー|
| ポイントフリー| ポイント| OK |
| ポイント| ポイント| OK |
それが私たちのテストに合格する理由です。 ポイントフリーまたはポイントフルスタイルのいずれかを使用しますが、順列は使用しないためです。
引数の数によって結果が変わります: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
|
| ------------ | ------------ | -------------- | -------- ------- |
| ポイントフリー| ポイントフリー| エラー| OK |
| ポイント| ポイントフリー| OK | エラー|
| ポイントフリー| ポイント| エラー| OK |
| ポイント| ポイント| OK | OK |
@inosikの問題を調査するためのすべての作業に感謝します! 本当に興味深い結果です。修正してみます...またはFableでポイントフリースタイルを絶対に禁止します;)
Fableでポイントフリースタイルを禁止する
では、 ["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 )
申し訳ありませんが、関数宣言でポイントフリースタイルを意味しました。 これをさらに調査するまで、すべての引数を明示的に宣言することをユーザーに推奨する警告を追加しました。 私はこれが今のところ大丈夫だと思います:)
Fable(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は正しい
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はファーストクラスの値として関数を操作することができませんか? :笑顔:
@inosikはい、それは可能ですが、ポイントフリースタイル(例: let add5 = add 5
)で非エイリアス関数を宣言できるため、すべてのケースが修正されるかどうかはわかりません。 しかし、正確には、呼び出しサイトを表示する際のポイントは、宣言を変更するだけでは不十分であるということです。その関数へのすべての呼び出しを追跡し、それに応じてASTを変更する必要があります。 このREPLサンプルのJSコードでは、F#コンパイラが最初に引数なしでop_Dollar
を呼び出し、次に実際の引数を1つずつ適用していることに注意してください。これは、多くの場合、Fableの不確実な最適化と競合します。
私はFCSリポジトリでこれに関する問題を開きました、彼らがそれについていくつかの光を当てることができるかどうか見てみましょう: https :
ああ、わかりました、わかりました。
ただし、上記のコメントのコード
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)
:部分的なアプリケーションでは、関数が別の型に包まれている場合は、多少壊れているようですResult
元スニペットでは、@ sandeepc24とによってOption
REPROサンプルインチカスタムのMaybe<'a>
タイプでも再現できます。
@inosikああ、Some
での関数のラッピング)であり、このコミットで修正する必要があります。
さて、これはOption
:+ 1で動作します:しかし、それは他のタイプには適用されません、これはカスタムタイプ( type Maybe<'a> = Just of 'a | Nothing
)とおそらくResult
まだ再現可能です
@inosik Resultも機能するはずです。これは、 @ 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つの引数とカウント。 :weary:
@inosik ...そしてそれはFableのテスト1400になります! さて、私はアプリケーションを修正するために別の試みをしました、私はあなたが別の失敗したテストを見つけるまで今度はもう少し時間がかかることを願っています:wink:
@alfonsogarciacaroに感謝します
Fable 1.3.3にアップデートしましたが、上記のcreateUser関数にまだ問題があります。
@ sandeepc24修正はまだリリースされていません。 しかし、Fable 1.3.3では、両方の演算子をポイントフリースタイル( let (<!>) = Result.map
)に変更すると、機能するはずです。 そうでない場合は、次のリリースを待つか、Fableを自分でビルドする必要があります。
@ sandeepc24 Fable 1.3.4がリリースされました。うまくいけば、これで問題が最終的に修正されます:)
私はこれをテストしました、そしてそれは今私のために働いています。 どうもありがとうございました。
素晴らしい、確認してくれてありがとう!
最も参考になるコメント
Option
すると、REPLに外部依存関係がなくても再現可能です。ただし、この変更で簡単に修正できます。
@ sandeepc24これをやってみてください: