Skip to main content
added 870 characters in body
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158

And as mentioned in comments, using Seq.choose is another great alternative, which opens us up to a little bit of extraction:

let private castItemSafe<'T> (item:obj) : 'T option =
    match item with
    | :? 'T as result -> Some result
    | _ -> None

let castSafe<'T> (items:IEnumerable) : 'T option seq =
    items
    |> Seq.cast<obj>
    |> Seq.map castItemSafe

let castSafeFilter<'T> (items:IEnumerable) : 'T seq =
    items
    |> Seq.cast<obj>
    |> Seq.choose castItemSafe

Because of the nature of our casting, we really only need to store the function which casts an individual item in one spot, since map will return all items and choose will naturally filter them out.

And as mentioned in comments, using Seq.choose is another great alternative, which opens us up to a little bit of extraction:

let private castItemSafe<'T> (item:obj) : 'T option =
    match item with
    | :? 'T as result -> Some result
    | _ -> None

let castSafe<'T> (items:IEnumerable) : 'T option seq =
    items
    |> Seq.cast<obj>
    |> Seq.map castItemSafe

let castSafeFilter<'T> (items:IEnumerable) : 'T seq =
    items
    |> Seq.cast<obj>
    |> Seq.choose castItemSafe

Because of the nature of our casting, we really only need to store the function which casts an individual item in one spot, since map will return all items and choose will naturally filter them out.

added 224 characters in body
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158

I previously touched on some basic composition stuff, and I want to continue that discussion with some new examples here.

We also have opportunity to use some function composition herein this code, which lends us to partial application, and allow us to not care about the node parameter to our functions.

We also have opportunity to use some function composition here, which lends us to partial application, and allow us to not care about the node parameter to our functions.

I previously touched on some basic composition stuff, and I want to continue that discussion with some new examples here.

We have opportunity to use some function composition in this code, which lends us to partial application, and allow us to not care about the node parameter to our functions.

added 758 characters in body
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158

We also have opportunity to use some function composition here, which lends us to partial application, and allow us to not care about the node parameter to our functions.

For example, we can take your titleText and descriptionText functions and simply omit the node parameter and our functions still work the same, thus leaving them agnostic to what's applied even moreso than they were. But what if we want to omit node from elementAsDateTimeOffset? Well we can't really do that as it's written, because the pipe-right (|>) operator expects a value, not a function. Now we can use the compose-right (>>) operator to eliminate that requirement:

let titleText =
    innerText "title"

let descriptionText =
    innerText "description"

let elementAsDateTimeOffset elementName =
    innerText elementName >> DateTimeOffset.Parse

let elementAsUri elementName =
    innerText elementName >> Uri

let linkUri =
    elementAsUri "link"

Now here is the part I really like: none of our signatures changed, but we no longer care about the parameter itself in these functions. We've partially applied the functions. For example, on titleText it is simply applying the "title" string to the innerText function (which expects two parameters) and returning a function that just needs an XmlNode applied to it.

I like to use this more and more in my code as it seems a bit clearer to me in the end. The net result is the same, and there's no significant advantage (that I know of - do note I'm no expert) to using one over the other, but it becomes a preference on the developer's end. (This also lends itself very easily towards the introduction of currying: that is, every function has one and only one parameter, even those with multiple parameters.)


We also have opportunity to use some function composition here, which lends us to partial application, and allow us to not care about the node parameter to our functions.

For example, we can take your titleText and descriptionText functions and simply omit the node parameter and our functions still work the same, thus leaving them agnostic to what's applied even moreso than they were. But what if we want to omit node from elementAsDateTimeOffset? Well we can't really do that as it's written, because the pipe-right (|>) operator expects a value, not a function. Now we can use the compose-right (>>) operator to eliminate that requirement:

let titleText =
    innerText "title"

let descriptionText =
    innerText "description"

let elementAsDateTimeOffset elementName =
    innerText elementName >> DateTimeOffset.Parse

let elementAsUri elementName =
    innerText elementName >> Uri

let linkUri =
    elementAsUri "link"

Now here is the part I really like: none of our signatures changed, but we no longer care about the parameter itself in these functions. We've partially applied the functions. For example, on titleText it is simply applying the "title" string to the innerText function (which expects two parameters) and returning a function that just needs an XmlNode applied to it.

I like to use this more and more in my code as it seems a bit clearer to me in the end. The net result is the same, and there's no significant advantage (that I know of - do note I'm no expert) to using one over the other, but it becomes a preference on the developer's end. (This also lends itself very easily towards the introduction of currying: that is, every function has one and only one parameter, even those with multiple parameters.)

added 758 characters in body
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158
Loading
Source Link
Der Kommissar
  • 20.1k
  • 4
  • 68
  • 158
Loading