Oh, yeah I like this. Yeah we definitely agree.
Re: type system, AFAIK you do like (let's assume something Go-ish here):
type Integer interface {
GetValue() int
Mul(i Integer) Integer
}
type Logger interface {
LogMessage()
}
type DataBlob struct {
value int
message string
}
func (db *DataBlob) GetValue() int {
return db.value
}
func (db *DataBlob) Mul(i Integer) Integer {
db.value *= i.GetValue()
return db
}
func (db *DataBlob) LogMessage() {
log.Println(db.message)
}
func triple(db *DataBlob) *DataBlob {
return db.Mul(&DataBlob{3, ""})
}
---In this way, you can always implement more interfaces onto DataBlob, and then modify your pipeline steps to take advantage of the new functionality. This example isn't really perfect, but it's reasonably illustrative. The thing is getting the compiler to know you can do different things with a given piece of data. In Go that's interfaces, in Haskell that's typeclasses, in Rust that's traits, blah.
P.S. This [0] Rosetta Code example made it pretty clear to me, so if you're the same kind of thinker maybe it'll help you.
But doesn't that mean that you're agreeing with me that OO and monads are doing the same thing (at least in this regard)?
And, can someone explain to me how the type system works here? I had thought that an advantage of monads were that you just had to change the type signature to take a monad rather than to take an int, but once you did that, it could take any monad. But that won't work, will it? If you're going to try to log from that function, then it has to be a monad that logs, doesn't it? It can't just be a generic monad; it has to be a specific one.