Injustice - Developers Among Us (SciFiDevCon 2024)
Boston Scala and F# Meetup Discusses Hybrid Functional Languages
1. Boston Area Scala Enthusiasts, April 11 th , 2011 • Microsoft NERD • Cambridge, MA let talk = things |> Seq.filter (fsharp >> cool) |> Seq.map scala |> Seq.take n
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16. C# 3.0 – can do this Func<Func<int,string,bool>, Func<int,string,Tuple<int,string>>,int,string, Tuple<int,string>> filtermap = (f, m, a, b) => { if (f(a,b)) { return m(a,b); } else { return Tuple.Create(a, b); } }; Func<int,string,bool> filter = ...; Func<int,string,Tuple<int,string>> map = ...; var t = filtermap(filter, map, 1, "Hello"); var tInt = t.Item1; var tString = t.Item2;
17.
18. C# 3.0/4.0 – a lot better than Java, but still not a full functional language “ Mads Torgersen, C# Product Manager http://blogs.msdn.com/b/madst/archive/2007/01/23/is-c-becoming-a-functional-language.aspx People who are functional programmers by night and have to write C# by day will find that the daily headache sets in a little later in the afternoon.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43. let arr = [| 1; 2; 3; 4; 5 |] let list = [ for i in 0 .. 2 .. 24 -> i * 4 ] type Country = { Name : string; Cities: string seq } let countries = [ { Name = "Spain"; Cities = ["Barcelona"; "Madrid" ] } { Name = "Germany"; Cities = ["Berlin"; "Frankfurt" ] } { Name = "USA"; Cities = ["Boston"; "New York ] } { Name = "India"; Cities = ["Bhopal"; "Mumbai" ] } ] let populations : IDictionary<string,long> = ... let mySeq = seq { for c in countries do for city in c.Cities do if city.StartsWith("b") then let pop = populations.["city"] yield city, country, pop }
63. /// Our asynchronous agent processor let agent = MailboxProcessor.Start(fun inbox -> let rec loop ticket = async { let! msg = inbox.Receive() match msg with // ... | Deposit(name,amt,channel) -> let t = ticket if accountMap.ContainsKey(name) then let a = accountMap.[name] a.Deposit(amt) |> ignore let msg = addMsg (t, name, "Deposit", amt, Success) channel.Reply(msg) else let msg = addMsg (t, name, "Deposit", amt, Failure("Account " + name + " not found")) channel.Reply(msg) return! loop (ticket + 1L)
64. // Scala style syntax helper - almost let (<!) (a : AccountAgent) (req : MessageRequest) = a.SendMessage req let agent = new AccountAgent(bankAccounts) let s = agent.Echo("Hello world!") let mutable n = agent.MessageCount() printfn "Messages: %d" n printfn "Making deposits..." agent <! DepositRequest("Alice", 1200M) |> ignore agent <! DepositRequest("Bob", 200M) |> ignore agent <! DepositRequest("Carol", 300M) |> ignore agent <! DepositRequest("Dave", 400M) |> ignore n <- agent <! MessageCountRequest |> getReply |> int64 printfn "Messages: %d" n
65.
66.
67.
68. // Simple Active Pattern – returns a boolean let (|UpperChar|) c = Char.ToUpper(c) // Partial Active Pattern – Some (with possible transformation) // or None let (|IsDigit|_|) c = if Char.IsDigit(c) then Some(int c) // convert char to an int else None // Active Pattern with parameters + reusing above APs let (|IsDigitInRange|_|) rangeStart rangeEnd c = match c with | IsDigit(n) -> if n >= rangeStart && n <= rangeEnd then Some(n) else None | _ -> None
69. // Partial Active Pattern let (|Match|_|) (regex : Regex) input = if regex.IsMatch(input) then Some(regex.Match(input)) else None // Active pattern - // "partitions" input into one of several "classes" let (|Zip|Country|State|City|Invalid|) s = match s with | Match regexZip m -> Zip(m |> result "zip", "", "", "") | Match regexCity m -> City("",resCountry m,resState m,m |> result "city") | Match regexState m -> State("", resCountry m, resState m, "") | Match regexCountry m -> Country("", resCountry m, "", "") | _ -> Invalid
70. // Using Active Pattern, this is simplified let parse input = match input with | Zip(z, _, _, _) -> { Country = ""; State = ""; City = ""; Zip = z } | Country(_, c, _, _) -> { Country = c; State = ""; City = ""; Zip = "" } | State(_, c, s, _) -> { Country = c; State = s; City = ""; Zip = "" } | City(_, co, st, ci) -> { Country = co; State = st; City = ci; Zip = "" } | Invalid -> { Country = ""; State = ""; City = ""; Zip = "" }
71. // Partial Active Pattern - returns Option. If Some(_) then returns a LocationInfo let (|ValidLocation|_|) input = match input with | Zip(z, _, _, _) -> Some({ Country = ""; State = ""; City = ""; Zip = z }) | City(_, co, st, ci) -> Some({ Country = co; State = st; City = ci; Zip = "" }) | _ -> None // Is this a "valid" location? // Use of "function" let parseIsValid = function | ValidLocation(loc) -> true | _ -> false // Same as... let parseIsValid2 input = match input with | ValidLocation(loc) -> true | _ -> false