ruxo
8/2/2015 - 3:58 PM

Exercise from https://github.com/DrBoolean/mostly-adequate-guide

source https://nuget.org/api/v2

nuget Newtonsoft.Json
open System

let maybe x f = function
  | None -> x
  | Some value -> f value

type Either<'a,'b> =
| Right of 'a
| Left of 'b

module Either =
  let map (f: 'a -> 'b) e=
    match e with
    | Right a -> Right (f a)
    | Left b -> Left b

  let unwrap f g = function
    | Left a -> f a
    | Right b -> g b

let getAge (now: DateTimeOffset) birthdate =
  let valid, date = DateTimeOffset.TryParse birthdate
  if valid
    then Right (now.Year - date.Year)
    else Left "Birth date could not be parsed"

let inline toString x = x.ToString()

//printfn "%A" (getAge DateTimeOffset.Now "2005-12-12")
//printfn "%A" (getAge DateTimeOffset.Now "20010704")

let fortune = ((+)1) >> toString >> ((+) "If you survive, you will be ")
let zoltar = (getAge DateTimeOffset.Now) >> (Either.unwrap id fortune) >> (printfn "%s")

//printfn "%A" (zoltar "2005-12-12")
//printfn "%A" (zoltar "balloons!")

module Storage =
  open System.Collections.Generic

  let private storage = Dictionary<string,string>()

  let getFromStorage key = fun () -> storage.[key]

type IO<'T> = { io: 'T }

module IO =
  let wrap f = { io = f }
  let from x = { io = fun () -> x }
  let map f x = { io = f << x.io }
  let run x = x.io()

let split (ch: char) (s: string) = s.Split ch

let path = IO.wrap <| fun () -> System.Environment.GetEnvironmentVariable "PATH"

let toArray = split ';'

let listPath = path |> IO.map (toArray >> Array.sort)

// printfn "%A" (IO.run listPath)

#load "task.fs"

open System.IO
open System.Threading.Tasks
open Folktale

let readFile (filename: string) =
  Task.wrap <|  fun (reject, resolve) ->
                  try
                    let reader = new StreamReader(filename)
                    reader.ReadToEndAsync()
                          .ContinueWith(fun (t: Task<string>) ->
                                          if t.IsFaulted then reject (t.Exception.Flatten() :> Exception) else resolve t.Result
                                          reader.Dispose())
                    |> ignore
                  with
                    | _ as ex -> reject ex

let x = readFile "paket.lock"
        |> Task.map (split('\n'))
        |> Task.map (Array.head)

let y = Task.from<unit,int> 3
        |> Task.map ((+) 1)

x |> Task.fork (printfn "%A", printfn "%s")
y |> Task.fork (id, printfn "value = %d")
#r "packages/Newtonsoft.Json/lib/net45/Newtonsoft.Json.dll"

open System
open System.Net
open System.Threading.Tasks
open System.IO

open Newtonsoft.Json.Linq

let inline trace tag x =
  printfn "%A %A" tag x

let img = sprintf """<img src="%s" />"""

module Str =
  let removeParentheses (s :string) = s.TrimEnd(')').TrimStart('(')
  let toString x = x.ToString()
  let join delimiter (xs :string seq) = String.Join(delimiter, xs)

module Json =
  let array property (o :JObject) = o.[property] :?> JArray
  let obj property (o:JObject) = o.[property] :?> JObject
  let value<'a> property (o :JObject) = o.[property].Value<'a>()

  let toObj (tok :JToken) = tok :?> JObject

module Impure =
  let getJSON callback (url :string) =
    let http = WebRequest.Create url :?> HttpWebRequest
    http.Accept <- "application/json"
    http.MaximumAutomaticRedirections <- 4
    
    let response = http.GetResponseAsync()
    
    let handler (t :WebResponse Task) :unit =
      use res = t.Result :?> HttpWebResponse
      use reader = new StreamReader(res.GetResponseStream())
      (callback << JObject.Parse << Str.removeParentheses << reader.ReadToEnd)()
    
    response.ContinueWith handler :> Task |> Async.AwaitTask

  let saveHtml file content = File.WriteAllText(file, content)

let url = sprintf "https://api.flickr.com/services/feeds/photos_public.gne?tags=%s&format=json&jsoncallback=?"

let mediaUrl = Json.obj "media" >> Json.value<string> "m"

let mediaToImg :JToken -> string = Json.toObj >> mediaUrl >> img

let images :JObject -> string seq = Json.array "items" >> Seq.map mediaToImg

let saveImages :JObject -> unit = images >> Str.join "\r\n" >> sprintf "<html><body>%s</body></html>" >> Impure.saveHtml "pictures.html"

let app = (Impure.getJSON saveImages) << url

app "piggy"
|> Async.RunSynchronously
let flip f a b = f b a

type Car = {
  name: string
  horsepower: int
  dollar_value: double
  in_stock: bool
}

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Car =
  let name car = car.name
  let in_stock car = car.in_stock
  let dollar_value car = car.dollar_value
  let horsepower car = car.horsepower

let CARS = [
    {name= "Ferrari FF"; horsepower= 660; dollar_value= 700000.; in_stock= true}
    {name= "Spyker C12 Zagato"; horsepower= 650; dollar_value= 648000.; in_stock= false}
    {name= "Jaguar XKR-S"; horsepower= 550; dollar_value= 132000.; in_stock= false}
    {name= "Audi R8"; horsepower= 525; dollar_value= 114200.0; in_stock= false}
    {name= "Aston Martin One-77"; horsepower= 750; dollar_value= 1850000.0; in_stock= true}
    {name= "Pagani Huayra"; horsepower= 700; dollar_value= 1300000.0; in_stock= false}
  ]

module re =
  open System.Text.RegularExpressions

  let ex s = Regex s
  let replace (r :Regex) (replacement :string) (what :string) = r.Replace(what, replacement)

let isLastInStock :Car seq -> bool = Car.in_stock << Seq.last

printfn "Exercise 1: %A" <| isLastInStock CARS

let nameOfFirstCar :Car seq -> string = Seq.head >> Car.name

printfn "Exercise 2: %s" <| nameOfFirstCar CARS

let _average (xs :double list) = (xs |> List.reduce (+)) / double(List.length xs)

let averageDollarValue = _average << List.map Car.dollar_value

printfn "Exercise 3: %.2f" <| averageDollarValue CARS

let _underscore = re.replace (re.ex @"\W+") "_"

let sanitizeNames = List.map _underscore

printfn "Exercise 4: %A" <| sanitizeNames ["Hello world"]

let fastestCar :Car seq -> string = Seq.sortBy Car.horsepower >> Seq.last >> Car.name >> (flip (+) <| " is the fastest")

printfn "Exercise 5: %s" <| fastestCar CARS