Skip to content

Commit

Permalink
Fix applicative operators with 3-arg functions
Browse files Browse the repository at this point in the history
  • Loading branch information
alfonsogarciacaro committed Nov 27, 2017
1 parent ddc63ff commit 51decad
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 32 deletions.
28 changes: 16 additions & 12 deletions src/dotnet/Fable.Core/AST/AST.Fable.Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -527,12 +527,17 @@ let rec ensureArity com argTypes args =
let expectedArgsLength = List.length expectedArgs
let actualArgsLength = List.length actualArgs
if expectedArgsLength < actualArgsLength then
List.skip expectedArgsLength actualArgs
|> List.map (fun t -> makeTypedIdent (com.GetUniqueVar()) t)
|> fun innerArgs ->
match List.skip expectedArgsLength actualArgs with
| [] -> failwith "Unexpected empty innerArgs list"
| [innerArgType] ->
let innerArgs = [makeTypedIdent (com.GetUniqueVar()) innerArgType]
let args = outerArgs@innerArgs |> List.map argIdentToExpr
makeApply com f.Range typ f args
Apply(f, args, ApplyMeth, typ, f.Range)
|> makeLambdaExpr innerArgs
| _ ->
let argArray = makeArray Fable.Any (List.map argIdentToExpr outerArgs)
CoreLibCall("CurriedLambda", Some "partialApply", false, [f; argArray])
|> makeCall f.Range typ
elif expectedArgsLength > actualArgsLength then
// if Option.isSome f.Range then
// com.AddLog("A function with less arguments than expected has been wrapped. " +
Expand Down Expand Up @@ -575,14 +580,13 @@ and makeApply com range typ callee (args: Expr list) =
| Type(Function(argTypes, _, _)) ->
let argsLength = List.length args
let argTypesLength = List.length argTypes
if argTypesLength < argsLength && argTypesLength >= 1 then
let innerArgs = List.take argTypesLength args
let outerArgs = List.skip argTypesLength args
Apply(callee, ensureArity com argTypes innerArgs, ApplyMeth,
Function(List.map Expr.getType outerArgs, typ, true), range)
|> makeApply com range typ <| outerArgs
elif argTypesLength > argsLength && argsLength >= 1 then
let argArray = makeArray Fable.Any args
if (argTypesLength <> argsLength) then
let innerArgs, outerArgs =
if argTypesLength < argsLength
then List.take argTypesLength args, List.skip argTypesLength args
else args, []
let innerArgs = ensureArity com argTypes innerArgs
let argArray = makeArray Fable.Any (innerArgs@outerArgs)
CoreLibCall("CurriedLambda", Some "partialApply", false, [callee; argArray])
|> makeCall range typ
else
Expand Down
49 changes: 29 additions & 20 deletions tests/Main/ApplicativeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@ let ``Infix applicative can be generated``() =
| _ -> failwith "expected Ok"
equal "1" r'

let inline apply (a:'a) (b:'b) =
let inline applyInline (a:'a) (b:'b) =
a <*> b

[<Test>]
let ``Infix applicative with inline functions can be generated``() =
let r = Ok 1
let a = Ok string
let r' = match apply a r with
let r' = match applyInline a r with
| Ok x -> x
| _ -> failwith "expected Ok"
equal "1" r'
Expand Down Expand Up @@ -711,41 +711,50 @@ let ``Partially applied curried lambdas capture this``() =
let f2 = f 2
f2 4 |> equal 14

let apply3 f x =
let apply f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None

let add3 a b c = a + b + c
let add4 a b c d = a+b+c+d

module Pointfree =
let (<!>) = Option.map
let (<*>) = apply3
let (<*>) = apply
let x = add3 <!> Some 40 <*> Some 1 <*> Some 1

module Pointful =
let (<!>) f x = Option.map f x
let (<*>) f x = apply3 f x
let (<*>) f x = apply f x
let x = add3 <!> Some 40 <*> Some 1 <*> Some 1

[<Test>]
// See https://github.com/fable-compiler/Fable/issues/1199#issuecomment-347101093
let ``Applying function options works``() =
let add1 = add4 <!> Some 1
let thenAdd2 = add1 <*> Some 2
let thenAdd3 = thenAdd2 <*> Some 3
let sum = thenAdd3 <*> Some 4
equal (Some 10) sum

[<Test>]
let ``Point-free and partial application work``() = // See #1199
equal Pointfree.x Pointful.x

let applyOptions f x =
match f, x with
| Some f, Some x -> Some (f x)
| _ -> None
module Results =
open FSharp.Core

let (<!>) f x = Option.map f x
let (<*>) f x = applyOptions f x
let add4 a b c d = a+b+c+d
let applyResults (f : Result<_, unit>) (x : Result<_, unit>) =
match f, x with
| Ok f, Ok x -> Ok (f x)
| _ -> Result.Error ()

[<Test>]
// See https://github.com/fable-compiler/Fable/issues/1199#issuecomment-347101093
let ``Applying function options works``() =
let add1 = add4 <!> Some 1
let thenAdd2 = add1 <*> Some 2
let thenAdd3 = thenAdd2 <*> Some 3
let sum = thenAdd3 <*> Some 4
equal (Some 10) sum
let (<!>) f x = Result.map f x
let (<*>) f x = applyResults f x

[<Test>]
// See https://github.com/fable-compiler/Fable/issues/1199#issuecomment-347190893
let ``Applicative operators work with three-argument functions``() =
let sum = add3 <!> Ok 1 <*> Ok 2 <*> Ok 3
equal (Ok 6) sum

0 comments on commit 51decad

Please sign in to comment.