I'm currently a student of FP. As I look around different syntax offer by different functional languages, I've come across a pattern in Elm sample code. I am curious about it.
Here is the sample code
myList = [{foo = "bar1"},{foo = "bar2"}]
foos = myList |> List.map .foo
In the last line here, List.map is being passed .foo. I believe this style is called point-free but what about the specific pattern of passing in an attribute to the List.map function?
Is this a more common thing? Is it possible to do this in Haskell? F#? Scala? Thanks for any help.
What is the (or is there a) formal (or informal ?) name for the pattern here? The property of an object is used as a short hand for a function that takes an object and calls said property on it?
If you think of your list as a "dataset" or "table", and consider each element in the list to be a "row", and the definition of the datatype of the elements as an enumeration of "attributes", then what you get is a kind of "projection" in the sense of relational algebra: https://en.wikipedia.org/wiki/Projection_(relational_algebra) .
Here is a Scala-example, which feels somewhat SQL-ish:
case class Row(id: Int, name: String, surname: String, age: Int)
val data = List(
Row(0, "Bob", "Smith", 25),
Row(1, "Charles", "Miller", 35),
Row(2, "Drew", "Shephard", 45),
Row(3, "Evan", "Bishop", 55)
)
val surnames = data map (_.surname)
val ages = data map (_.age)
val selectIdName = data map { row => (row.id, row.name) }
println(surnames)
// List(Smith, Miller, Shephard, Bishop)
println(selectIdName)
// List((0,Bob), (1,Charles), (2,Drew), (3,Evan))
Here, _.fieldName is a short syntax for an inline function literal of type Row => TypeOfTheField.
In Haskell, it's kind of trivial, because the declaration of a record datatype automatically brings all the getter functions into scope:
data Row = Row { id :: Int
, name :: String
, surname :: String
, age :: Int
} deriving Show
main = let dataset = [ Row 0 "Bob" "Smith" 25
, Row 1 "Charles" "Miller" 35
, Row 2 "Drew" "Shephard" 45
, Row 3 "Evan" "Bishop" 55
]
in print $ map name dataset
-- prints ["Bob","Charles","Drew","Evan"]
Even Java has something similar since version 8:
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
class JavaProjectionExample {
private static class Row {
private final int id;
private final String name;
private final String surname;
private final int age;
public Row(int id, String name, String surname, int age) {
super();
this.id = id;
this.name = name;
this.surname = surname;
this.age = age;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public int getAge() {
return this.age;
}
}
public static void main(String[] args) {
List<Row> data = Arrays.asList(
new Row(0, "Bob", "Smith", 25),
new Row(1, "Charles", "Miller", 35),
new Row(2, "Drew", "Shephard", 45),
new Row(3, "Evan", "Bishop", 55)
);
List<Integer> ids = data.stream().map(Row::getId).collect(toList());
List<String> names = data.stream().map(Row::getName).collect(toList());
System.out.println(ids);
System.out.println(names);
}
}
Here, Row::getterName is a special syntax for getter methods, it is a value of type Function<Row, FieldType>.
This is actually not point free, but rather syntactic sugar and the pipe forward operator. For point free see this article.
This can be written in fsharp as follows:
let foos = myList |> List.map (fun x -> x.foo)
And you can see immediately that this is equivalent to
List.map (fun x -> x.foo) myList
So the pipe operator just flips the arguments and makes it easy to chain operations together. So you pass your function and a list to the map. And the syntactic sugar in Elm allows you to skip the function parameter, by just writing out .foo. I think that feature is quite handy, btw.
Point-free would be when you avoid specifying the parameters of the function. It's typical FP but can be difficult to read once it gets complicated.
An example:
let mySum x y = x + y
//val mySum : x:int -> y:int -> int
mySum 4 7 //11
This is point free:
let mySum2 = (+)
//val mySum2 : (int -> int -> int)
mySum2 4 7 //11
Related
I have a list of items which share a base class but are very different, and would like to sort them first by their class, then by a comparator specific to that class.
Eg SubtypeA should be sorted by the property foo which is specific to that class, while SubTypeB should be sorted by the properties bar1 then bar2 which are specific to that class, and I need to sort lists containing both.
The actual order of the sort is unimportant, just that it is consistent within a runtime so that two lists of these objects can be checked for equality by first sorting them.
(Up until this point I have just used a lazy property that adds the object to a set and checks its index, thus giving equal objects the same sortkey, but this cache is growing to ludicrous sizes that make things very slow)
How can I group these objects by their class to then use a class specific comparator?
Here is something that might serve your needs.
We supply separate comparator for all subtypes, and simply group all by type and sort each group with it's own comparator, after that simply sort groups by their class name and flatten elements from each group in consecutive manner.
Here is code example demonstrating it.
added utility function sortedUsing to perform this sorting
added an utility type TypeComparator just to have more convenient way to pass type safe Class + Comparator
fun <T : Any> List<T>.sortedUsing(
vararg typeComparators: TypeComparator<out T>
): List<T> {
#Suppress("UNCHECKED_CAST")
fun <R : T> TypeComparator<R>.sort(list: List<T>): List<R> = (list as List<R>).sortedWith(comparator)
val comparators = typeComparators.associateBy { it.type }
return groupBy { it::class }
.mapValues { (klass, list) ->
val typeComparator = comparators[klass]
?: typeComparators.firstOrNull { klass.isSubclassOf(it.type) }
?: list.firstOrNull()?.tryMakeComparator()
?: throw IllegalArgumentException("Missing comparator for type: $klass")
typeComparator.sort(list)
}
.map { it }
.sortedBy { it.key.qualifiedName }
.flatMap { it.value }
}
#Suppress("UNCHECKED_CAST")
private fun <T : Any> T.tryMakeComparator(): TypeComparator<T>? {
if (this !is Comparable<*>) {
return null
}
return TypeComparator(this::class as KClass<T>, Comparator { o1, o2 ->
val c1 = o1 as Comparable<Comparable<T>>
val c2 = o2 as Comparable<T>
c1.compareTo(c2)
})
}
data class TypeComparator<T : Any>(
val type: KClass<T>,
val comparator: Comparator<T>
)
You could also supply comparator for type if you'd like to, because default in snippet above is to order typed groups by class full name.
With some better way of accumulating elements of some type, you could get rid of unchecked list cast.
Usage example:
open class Base
data class SubtypeA(
val foo: Int
) : Base()
data class SubtypeB(
val bar1: String,
val bar2: String
) : Base()
fun main() {
val list = listOf(
SubtypeA(5),
SubtypeB("foo", "x"),
SubtypeA(42),
SubtypeA(2),
SubtypeB("bar", "y"),
SubtypeB("bar", "x")
)
val sorted = list.sortedUsing(
TypeComparator(SubtypeA::class, Comparator.comparing { a: SubtypeA -> a.foo }),
TypeComparator(SubtypeB::class, Comparator.comparing { b: SubtypeB -> b.bar1 }.thenComparing { b: SubtypeB -> b.bar2 })
)
sorted.forEach { println(it) }
// prints:
// SubtypeA(foo=2)
// SubtypeA(foo=5)
// SubtypeA(foo=42)
// SubtypeB(bar1=bar, bar2=x)
// SubtypeB(bar1=bar, bar2=y)
// SubtypeB(bar1=foo, bar2=x)
}
Using Monocle I can define a Lens to read a case class member without issue,
val md5Lens = GenLens[Message](_.md5)
This can used to compare the value of md5 between two objects and fail with an error message that includes the field name when the values differ.
Is there a way to produce a user-friendly string from the Lens alone that identifies the field being read by the lens? I want to avoid providing the field name explicitly
val md5LensAndName = (GenLens[Message](_.md5), "md5")
If there is a solution that also works with lenses with more than one component then even better. For me it would be good even if the solution only worked to a depth of one.
This is fundamentally impossible. Conceptually, lens is nothing more than a pair of functions: one to get a value from object and one to obtain new object using a given value. That functions can be implemented by the means of accessing the source object's fields or not. In fact, even GenLens macro can use a chain field accessors like _.field1.field2 to generate composite lenses to the fields of nested objects. That can be confusing at first, but this feature have its uses. For example, you can decouple the format of data storage and representation:
import monocle._
case class Person private(value: String) {
import Person._
private def replace(
array: Array[String], index: Int, item: String
): Array[String] = {
val copy = Array.ofDim[String](array.length)
array.copyToArray(copy)
copy(index) = item
copy
}
def replaceItem(index: Int, item: String): Person = {
val array = value.split(delimiter)
val newArray = replace(array, index, item)
val newValue = newArray.mkString(delimiter)
Person(newValue)
}
def getItem(index: Int): String = {
val array = value.split(delimiter)
array(index)
}
}
object Person {
private val delimiter: String = ";"
val nameIndex: Int = 0
val cityIndex: Int = 1
def apply(name: String, address: String): Person =
Person(Array(name, address).mkString(delimiter))
}
val name: Lens[Person, String] =
Lens[Person, String](
_.getItem(Person.nameIndex)
)(
name => person => person.replaceItem(Person.nameIndex, name)
)
val city: Lens[Person, String] =
Lens[Person, String](
_.getItem(Person.cityIndex)
)(
city => person => person.replaceItem(Person.cityIndex, city)
)
val person = Person("John", "London")
val personAfterMove = city.set("New York")(person)
println(name.get(personAfterMove)) // John
println(city.get(personAfterMove)) // New York
While not very performant, that example illustrates the idea: Person class don't have city or address fields, but by wrapping data extractor and a string rebuild function into Lens, we can pretend it have them. For more complex objects, lens composition works as usual: inner lens just operates on extracted object, relying on outer one to pack it back.
I'd like a container class that I can extend with some number of traits to contain groups of default vals that can later be changed in an immutable way. The traits will hold certain simple pieces of data that go together so that creating the class with a couple of traits will create an object with several collections of default values.
Then I'd like to be able to modify any of the vals immutably by copying the object while changing one new value at a time.
The class might have something like the following:
class Defaults(val string: String = "string", val int: Int = "int")
Then other traits like this
trait MoreDefaults{
val long: Long = 1l
}
Then I'd like to mix them when instantiated to build my the particular needed set of defaults
var d = new Defaults with MoreDefaults
and later to something like:
if (someFlag) d = d.copy( long = 1412341234l )
You can do something like this with a single case class but I run out of params at 22. But I'll have a bunch of groupings of defaults I'd like to mixin depending on the need, then allow changes to any of them (class defined or trait defined) in an immutable way.
I can stick a copy method in the Defaults class like this:
def copy(
string: String = string,
int: Int = int): Defaults = {
new Defaults(string, int)
}
then do something like
var d = new Defaults
if (someFlag) d = d.copy(int = 234234)
Question ====> This works for values in the base class but I can't figure how to extend this to the mixin traits. Ideally the d.copy would work on all vals defined by all of the class + traits. Overloading is trouble too since the vals are mainly Strings but all of the val names will be unique in any mix of class and traits or it is an error.
Using only classes I can get some of this functionality by having a base Defaults class then extending it with another class that has it's own non-overloaded copyMoreDefault function. This is really ugly and I hope a Scala expert will see it and have a good laugh before setting me straight--it does work though.
class Defaults(
val string: String = "one",
val boolean: Boolean = true,
val int: Int = 1,
val double: Double = 1.0d,
val long: Long = 1l) {
def copy(
string: String = string,
boolean: Boolean = boolean,
int: Int = int,
double: Double = double,
long: Long = long): Defaults = {
new Defaults(string, boolean, int, double, long)
}
}
class MoreDefaults(
string: String = "one",
boolean: Boolean = true,
int: Int = 1,
double: Double = 1.0d,
long: Long = 1l,
val string2: String = "string2") extends Defaults (
string,
boolean,
int,
double,
long) {
def copyMoreDefaults(
string: String = string,
boolean: Boolean = boolean,
int: Int = int,
double: Double = double,
long: Long = long,
string2: String = string2): MoreDefaults = {
new MoreDefaults(string, boolean, int, double, long, string2)
}
}
Then the following works:
var d = new MoreDefualts
if (someFlag) d = d.copyMoreDefaults(string2 = "new string2")
This method will be a mess if Defaults get's changed parameters! All the derived classes will have to be updated--ugh. There must be a better way.
I don't think I'm strictly speaking answering your question, rather suggesting an alternative solution. So your having problems with large case classes, e.g.
case class Fred(a: Int = 1, b: Int = 2, ... too many params ... )
What I would do is organize the params into more case classes:
case class Bar(a: Int = 1, b: Int = 2)
case class Foo(c: Int = 99, d: Int = 200)
// etc
case class Fred(bar: Bar = Bar(), foo: Foo = Foo(), ... etc)
Then when you want to do a copy and change, say one of the values of Foo you do:
val myFred: Fred = Fred()
val fredCopy: Fred = myFred.copy(foo = myFred.foo.copy(d = 300))
and you need not even define the copy functions, you get them for free.
How in Scala I can define local variable in primary constructor?
I need to solve this exercise from Scala for the impatient book:
Write a class Person with a primary constructor that accepts a string
containing a first name, a space, and a last name, such as new
Person("Fred Smith"). Supply read-only properties firstName and
lastName. Should the primary constructor parameter be a var, a val, or
a plain parameter? Why?
And for now my solution looks like this:
class Person(firstLast: String) {
private[this] val firstLastAsArr = firstLast.trim.split(" ")
val firstName = firstLastAsArr (0)
val lastName = firstLastAsArr (1)
}
How I can restrict firstLastAsArr variable visibility to primary constructor scope (now it have class scope)?
One solution is to initialize firstName and lastName at once, thereby allowing to turn firstLastAsArr into a local temporary value inside your initialization block:
class Person(firstLast: String) {
val (firstName, lastName) = {
val firstLastAsArr = firstLast.trim.split(" ")
(firstLastAsArr(0), firstLastAsArr(1))
}
}
It is not a general answer, but in this particular way you may write:
val Array(firstName, lastName) = firstLast.trim.split(" ")
You don't strictly need the intermediate variable:
class Person(firstLast: String) {
val (firstName, lastName) =
firstLast.trim.split(" ") match {case Array(first, last) => (first, last)}
}
However, if your transformation from firstLast to firstName and lastName grows a big longer, for example, because you check that there is exactly one first and one last name, then I would encapsulate the whole splitting-business in a dedicated method:
class Person(firstLast: String) {
val (firstName, lastName) = split(firstLast)
private def split(firstLast: String): (String, String) = {
val firstLastAsArr = firstLast.trim.split(" ")
...
(first, last)
}
}
Pattern matching in constructor works just fine, but you should consider moving such logic from constructor to factory method:
case class Person(firstName: String, lastName: String)
object Person{
def apply(firstLast: String) = {
val firstLastAsArr = firstLast.trim.split(" ")
new Person(firstLastAsArr(0), firstLastAsArr(1))
}
}
val p = Person("My Title")
Pattern maching in primary constructor works well
class Person(_fullName:String) {
val (firstName, lastName) = _fullName.split(" ") match {
case Array(x:String, y:String, _*) => (x,y)
case _ => (null,null)
}
}
See my github for full answer
https://github.com/BasileDuPlessis/scala-for-the-impatient/blob/master/src/main/scala/com/basile/scala/ch05/Ex07.scala
In C# I can declare a list declaratively, in other words declare its structure and initialise it at the same time as follows:
var users = new List<User>
{
new User {Name = "tom", Age = 12},
new User {Name = "bill", Age = 23}
};
Ignoring the differences between a List in .Net and a List in Scala (ie, feel free to use a different collection type), is it possible to do something similar in Scala 2.8?
UPDATE
Adapting Thomas' code from below I believe this is the nearest equivalent to the C# code shown:
class User(var name: String = "", var age: Int = 0)
val users = List(
new User(name = "tom", age = 12),
new User(name = "bill", age = 23))
What about:
case class User(name: String, age: Int)
val users = List(User("tom", 12), User("bill", 23))
which will give you:
users: List[User] = List(User(tom,12), User(bill,23))
val users = User("tom", 12) :: User("bill", 23) :: Nil
You could also use Scalas tupel class:
val users = ("tom", 12) :: ("bill", 23) :: Nil
Or you can create objects without use of explicit class defined in your compilation module this wayList(
new {var name = "john"; var age = 18},
new {var name = "mary"; var age = 21}
)
Note, that this code has some serious drawback, it will create an anonymous class per each new.
Adapting Thomas' code from below I believe this is the nearest equivalent to the C# code shown:
class User(var name: String = "", var age: Int = 0)
val users = List(
new User(name = "tom", age = 12),
new User(name = "bill", age = 23))
It is subtly different to the way the C# code behaves because we are providing an explicit constructor with default values rather than using the no args constructor and setting properties subsequently, but the end result is comparable.