Fable: ポイントフリースタイルで宣言された関数の適用は失敗します

作成日 2017年10月22日  ·  46コメント  ·  ソース: fable-compiler/Fable

説明

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

全てのコメント46件

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 updatedotnet restoreます。 または、 @ inosikサンプルのようにテストを追加して、コードをローカルでテストできるようにしてください。 どうもありがとうございました!

@ alfonsogarciacaro-ご迷惑をおかけして申し訳ありませんが、これは修正されているのでしょうか。

私は同じことを不思議に思っていました;)あなたは最新バージョンでチェックしましたか?

1.3にアップデートしましたが、まだ問題があります:-(

これが私のpaket.lockファイルの画像です。

image

@ 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 )

申し訳ありませんが、関数宣言でポイントフリースタイルを意味しました。 これをさらに調査するまで、すべての引数を明示的に宣言することをユーザーに推奨する警告を追加しました。 私はこれが今のところ大丈夫だと思います:)

screen shot 2017-11-21 at 11 41 32 am

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の、ポイントフリー(左)スタイルとポイントフル(右)スタイルの違いを確認してください。 残念ながら、これらのケースを検出し、すべての状況(部分適用など)を解決するためのすべての試みは失敗しました😞

screen shot 2017-11-25 at 2 13 30 pm

私は警告を問題のあるケースに限定するように取り組んでいます、そして私はほとんどそれを持っていると思います。 これがおそらく今のところ唯一の解決策になるでしょう。

@inosik私はそれを試しましたが、3つ以上のパラメーターがある場合にも失敗します。

@alfonsogarciacaroそのスクリーンショットは、呼び出しサイトを示しています。私が意味したのは、宣言でした。

let add a b = a + b
let sumOf = add

sumOfaddエイリアスであることを検出できますか? 次に、次のようなものを生成できます。

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がリリースされました。うまくいけば、これで問題が最終的に修正されます:)

私はこれをテストしました、そしてそれは今私のために働いています。 どうもありがとうございました。

素晴らしい、確認してくれてありがとう!

このページは役に立ちましたか?
0 / 5 - 0 評価