F# list and arrays (but not sequences and computation expressions) allow both data and computations that produce data, e.g.
[ 1; 2 ]
[ yield 1; yield 2 ]
[ yield 1; yield 2; match a with A -> yield 1 | B -> () ]
but not
[ 1; 2; match a with A -> yield 1 | B -> () ]
This means that adding a single computation to an otherwise simple data list requires you to add yield everywhere. This particularly bites computed views in Fable/Elmish.
It is possible we could be more tolerant here and interpret expressions in the list which are not unit-typed and are at the fringes of control-flow expressions as an implicit yield. This would allow
[ 1; 2; match a with A -> 1 | B -> () ]
Note that the yield would, I think, still be required in the case of in element that is a control construct match, let, if etc.
It's possible that making such a more liberal interpretation can confuse people in other ways or be a breaking change. For example,
- the branches of the
match no longer match in type - one is unit-typed and the other is not. This means the expression can't be extracted into a function However this is already the case - if the expression syntax contains yield then it is part of a generator, and is not an expression.
- existing code might already contain non-unit-valued items that are currently being ignored (with a warning). In this new interpretation these would now be yielded.
- Lists of unit values would not satisfy this
We would also need to consider whether the construct also applies to sequence expressions (implicit yield) and computation expressions (implicit yield/return).
Example
Consider this:
div [ClassName ("form-group has-feedback " + authorStatus) ] [
yield div [ClassName "input-group"][
yield span [ClassName "input-group-addon"] [span [ClassName "glyphicon glyphicon-user"] [] ]
yield input [
Key ("Author_" + model.NewBookId.ToString())
HTMLAttr.Type "text"
Name "Author"
DefaultValue model.NewBook.Authors
ClassName "form-control"
Placeholder "Please insert authors"
Required true
OnChange (fun (ev:React.FormEvent) -> dispatch (AuthorsChanged !!ev.target?value))]
match model.AuthorsErrorText with
| Some e -> yield span [ClassName "glyphicon glyphicon-remove form-control-feedback"] []
| _ -> ()
]
match model.AuthorsErrorText with
| Some e -> yield p [ClassName "text-danger"][str e]
| _ -> ()
]
Note that the presence of one match requires adding lots of yield. This would become:
div [ClassName ("form-group has-feedback " + authorStatus) ] [
div [ClassName "input-group"][
span [ClassName "input-group-addon"] [span [ClassName "glyphicon glyphicon-user"] [] ]
input [
Key ("Author_" + model.NewBookId.ToString())
HTMLAttr.Type "text"
Name "Author"
DefaultValue model.NewBook.Authors
ClassName "form-control"
Placeholder "Please insert authors"
Required true
OnChange (fun (ev:React.FormEvent) -> dispatch (AuthorsChanged !!ev.target?value))]
match model.AuthorsErrorText with
| Some e -> yield span [ClassName "glyphicon glyphicon-remove form-control-feedback"] []
| _ -> ()
]
match model.AuthorsErrorText with
| Some e -> yield p [ClassName "text-danger"][str e]
| _ -> ()
]
Pros and Cons
The advantages of making this adjustment to F# are clearer code in the common case
The disadvantages of making this adjustment to F# are
- it's a corner-case breaking change
- it would require a type-directed rule
yield! or return! would still be required to yield another computed thing. Forgetting to add yield! or return! might be even more confusing than it already is
Extra information
Estimated cost (XS, S, M, L, XL, XXL): S
cc @forki
Affidavit (please submit!)
Please tick all that apply:
F# list and arrays (but not sequences and computation expressions) allow both data and computations that produce data, e.g.
but not
This means that adding a single computation to an otherwise simple data list requires you to add
yieldeverywhere. This particularly bites computed views in Fable/Elmish.It is possible we could be more tolerant here and interpret expressions in the list which are not unit-typed and are at the fringes of control-flow expressions as an implicit yield. This would allow
Note that the
yieldwould, I think, still be required in the case of in element that is a control constructmatch,let,ifetc.It's possible that making such a more liberal interpretation can confuse people in other ways or be a breaking change. For example,
matchno longer match in type - one is unit-typed and the other is not. This means the expression can't be extracted into a function However this is already the case - if the expression syntax containsyieldthen it is part of a generator, and is not an expression.We would also need to consider whether the construct also applies to sequence expressions (implicit yield) and computation expressions (implicit yield/return).
Example
Consider this:
Note that the presence of one
matchrequires adding lots ofyield. This would become:Pros and Cons
The advantages of making this adjustment to F# are clearer code in the common case
The disadvantages of making this adjustment to F# are
yield!orreturn!would still be required to yield another computed thing. Forgetting to addyield!orreturn!might be even more confusing than it already isExtra information
Estimated cost (XS, S, M, L, XL, XXL): S
cc @forki
Affidavit (please submit!)
Please tick all that apply: