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:
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.