简体   繁体   中英

Accessing DynamicJsonArray in F#

I'm looking into F# for personal 'fun' reasons and to explore thinking in a functional way. I'm trying to duplicate the functionality of this other code snippet I wrote this morning: here .

I've written this code below, however it seems I can't really access items in my for ... in statement.

open System
open System.Net
open System.Web.Helpers

let data = Json.Decode((new WebClient()).DownloadString("http://sw.cs.wwu.edu/~fugiera/matches"))

let myList = [for x : DynamicJsonArray in downcast data do if x?status != "complete" then yield x?home_team.goals ]

Console.ReadKey() |> ignore

I'm really just trying to wrap my head around everything right now, and could use a pointer or two!

Thanks

First, your for loop is casting in the wrong place. You want to cast data to DynamicJsonArray , not x . You also need to cast x to DynamicJsonObject .

let myList = [
    for x in (data :?> DynamicJsonArray) do
        let x = x :?> DynamicJsonObject
        ... 

F# doesn't have built-in support for dynamic objects like this the way C# does, so you can't use a standard operator like ? to get at the properties of your object.

I spent about 20 seconds attempting to figure out how one does extract dynamic properties using normal APIs, but got bored.

Luckily, F# has a feature called Type Providers which in some ways are like dynamic objects, but on super steroids. They would work perfectly here.

Add a reference to the NuGet package FSharp.Data and try this code on for size:

open FSharp.Data

type WorldCup = JsonProvider<"http://worldcup.sfg.io/matches">

for game in WorldCup.GetSamples() do
    match (game.Status, game.HomeTeam.Record, game.AwayTeam.Record) with
    | ("completed", Some(ht), Some(at)) ->
        printfn "%s %d vs %s %d" ht.Country ht.Goals at.Country at.Goals
    | _ -> () 

If you just want working code, there ya go. For some more details, read on.

Some things to notice, comparing to your linked C# code:

  • You get intellisense on the JSON objects, showing you the available properties (don't get that in C#)
  • If you typo a property name, or make an assumption about a property always being available when it isn't, your code won't build. This prevents all kinds of runtime errors that can happen in C#.

In particular, notice that in the raw JSON, game.HomeTeam is not always present (ie for not-yet-played games this is not populated). Your C# accesses game.home_team.country, game.home_team.goals anyways, because you are filtering on status . That works ok for now, but in general it's risky since that could blow up at runtime.

In F#, the JSON type provider notices that HomeTeam and AwayTeam are not always present, so it exposes them as option types . You are required by the type system to consider what to do when those values are missing. That's a good thing!

So you see that the code checks for 3 things: 1. status = "completed" 2. HomeTeam is defined (is Some(homeTeam) , not None ) 3. AwayTeam is defined. If so, we print the details. If not, skip it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM