What I want, expressed in Haskell notation:
type Errors = [String]
type Warnings = [Keyword]
data ParseResult a = ParseSuccess a Warnings | ParseFailure ErrorsMy attempt at writing it in Typed Clojure:
| scala> trait A { type B } | |
| defined trait A | |
| scala> class Foo(val a: A)(val b: a.B) | |
| <console>:12: error: not found: value a | |
| class Foo(val a: A)(val b: a.B) | |
| ^ | |
| scala> case class Foo(a: A)(b: a.B) | |
| <console>:12: error: not found: value a |
| abstract class Enum[E : Manifest] { | |
| def all: Seq[E] | |
| def asString: String | |
| def fromString(string: String): Option[E] = { | |
| all.find(_.asString == string) | |
| } | |
| } | |
| abstract class TolerantEnum[E : Manifest] { |
What I want, expressed in Haskell notation:
type Errors = [String]
type Warnings = [Keyword]
data ParseResult a = ParseSuccess a Warnings | ParseFailure ErrorsMy attempt at writing it in Typed Clojure:
| user=> (use 'match-block.core) | |
| nil | |
| user=> (defn collect [pf xs] | |
| #_=> (->> xs | |
| #_=> (filter #(defined-at? pf %)) | |
| #_=> (map pf))) | |
| #'user/collect | |
| user=> (def sample-list |
| scala> def foo[R <: { def f1: Int }](x: R): (R, Int) = (x, x.f1) | |
| foo: [R <: AnyRef{def f1: Int}](x: R)(R, Int) | |
| scala> val x = new { | |
| | def f1 = 90 | |
| | def f2 = "hello" | |
| | } | |
| x: AnyRef{def f1: Int; def f2: String} = $anon$1@adeb0ee | |
| scala> foo(x)._1.f2 |
| # Method references, with partial application. | |
| class Array | |
| def to_proc | |
| lambda { |obj, *more_args| obj.send(*self, *more_args) } | |
| end | |
| end | |
| # Sample use. | |
| [3, 4, 9].map &[:+, 3] |
| data Person = Person { name :: String } deriving (Eq, Show) | |
| let people = [ Person "Jacob", Person "Rubin", Person "Arjun" ] | |
| sortBy (comparing name) people | |
| -- [Person {name = "Arjun"},Person {name = "Jacob"},Person {name = "Rubin"}] | |
| sortBy (comparing (Down . name)) people | |
| -- [Person {name = "Rubin"},Person {name = "Jacob"},Person {name = "Arjun"}] |
We receive JSON objects with hundreds of fields in them. About a dozen or so are utilized by business logic. The rest are useless, but need to be retained, because the JSONs massaged/enriched/amended by our system are later consumed by other systems.
Given the number of fields, converting JSONs to case classes is not an option.
Dealing with naked JSONs is also not an attractive option; need some way to attach domain meaning to it.
For this purpose, we use this thing called "embedded document" pattern. Fowler's post on the topic - http://martinfowler.com/bliki/EmbeddedDocument.html.
This is what it (roughly) looks like:
| import net.liftweb.{json => L} | |
| import play.api.libs.{json => P} | |
| def liftJsonToPlayJson(liftJson: L.JValue): P.JsValue = liftJson match { | |
| case L.JBool(b) => P.JsBoolean(b) | |
| case L.JDouble(n) => P.JsNumber(n) | |
| case L.JInt(n) => P.JsNumber(BigDecimal(n)) | |
| case L.JString(s) => P.JsString(s) | |
| case L.JArray(values) => P.JsArray(values.map(liftJsonToPlayJson)) | |
| case L.JObject(fields) => P.JsObject(fields.map(f => f.name -> liftJsonToPlayJson(f.value))) |
| haskell> -- This is an attempt to distill a misunderstanding that pipe "operator" is just a | |
| haskell> -- bad copy of OO dot. | |
| haskell> | |
| haskell> -- Let me define a pipe operator first. (Haskell doesn't ship with this by default.) | |
| haskell> let (|>) = flip ($) | |
| haskell> | |
| haskell> -- A typical usage that looks like the "OO dot". | |
| haskell> "hello" |> length | |
| 5 | |
| haskell> -- However such comparison is only superficial. With `|>`, the only constraint on the function |