I have code like this
final class MyType(url: URL, dest: Path)
object MyType {
implicit val mytype: MyType = new MyType(new URL("https://example.com/mydata"), Paths.get("/tmp/mydata"))
}
where
I then attempt to initialize with cats Monad
import MyType._
Monad[MyType]
But the compiler returns message saying
No given instance of type cats.Monad[examples.App.MyType] was found for parameter instance of method apply in object Monad
I searched and found a thread at SO - functional programming - How to create an instance of typeclass Monad[F[_]] of a custom type constructor in Scala Cats - Stack Overflow
Is implementing Monad myself the only way to achieve that? Or what is the general way to provide a custom type for cats’ Monad instance?
I have this question because I don’t know how to implement tailRecM
.
Many thanks
1 Like
That type can not even form a monad from a kind perspective.
Anyways, why do you want to form a Monad
for your type? You rarely need to implement your own Monad
, you simply use existing ones.
This sounds like an XY problem, what is the meta-problem that lead you to this rabbit hole?
1 Like
Asking kind of the same question as @BalmungSan from a different perspective: what would the flatMap()
function do with this type?
From a purely pragmatic POV, that’s sort of the definition of a monad. If you have a sensible definition of flatMap()
, you have something that at least roughly fits; if not, not.
In practice, that means asking:
- What does
map()
mean? That is, when you apply a function to this data type, what would come out?
- What does
flatten()
mean? If you have one of these inside itself – a MyType
that contains a MyType
– what does it mean?
This particular MyType
can’t be a Monad, really – a Monad always has a type parameter, because otherwise the “MyType containing a MyType” doesn’t make sense. But those are the rough guidelines for thinking about when it might make sense.
3 Likes
Ok. I completely misunderstand the usage. Actually below the code is what I need instead. I misunderstand the purpose that the parameter T provided to Monad - T should be things like Option, Either. Then I explicitly provide my object to pure, or when calling flatMap.
case class MyObject(repoistory: URL, localDest: Path)
def main(args: Array[String]): Unit = {
val objM = Monad[Option].pure(MyObject(new URL("https://example.com/docs"), Paths.get("/tmp/example")))
objM.flatMap{ myobj => println(myobj); Option(myobj)}
}
Thanks for asking me questions like you simply use existing one
/ This particular
MyType can’t be a Monad,...
!! Many thanks!
Right, usually it is not named T
but rather F[_]
, not the [_]
that means that F
is a type of kind * -> *
rather than one of kind *
Which means, it has to be things like Option
, List
, Either[X, _]
, but can’t be things like Int
, MyType
or List[Int]
Uhm, btw, is this just for demonstration purposes?
Because that code is actually just complicating something simple and actually “wrong” due to the println
.
I ask because I have a feeling you are going down a rabbit hole.
Maybe it may be good if you can explain what is your motivation here? What exactly are you trying to do / learn / practice?
2 Likes
The code is just for demonstrating purpose. println(...)
is the logic where it will be replaced with my own business logic. Then create another new F object like Option that continues the workflow.
Monad[Option].flatMap(Option(MyObject(new URL("https://example.com/docs"), Paths.get("/tmp/example")))){ myobj =>
println(myobj); Option(myobj.copy(localDest=Paths.get("/tmp/abc")))
}.flatMap{ myobj1 =>
println(myobj1); Option(myobj1.copy(localDest=Paths.get("/tmp/xyz")))
}...
But please correct me if it’s not the right way to do that.
My main purpose is just to exploit cats.Monad performing some workflow (dependency related) operations. For instance, access the DB and perform some CRUDs, where the code will need to get authed, and CRUDs operations may affect the state for the later operations. Or something like git in that the repository needs to be inited; then operations like add and commit can be performed.
Thanks
Okay, so here Option
is also just a placeholder for another data type like IO
?
Because, it sounds like you are trying to get into what is known as the “Programs as Values” paradigm, but that requires a proper data type, not any Monad
like Option
.
I have some examples and resources about that here: GitHub - BalmungSan/programs-as-values: Source code of the programs as values presentation
And during the next week, I will be adding a link to the English recording of the talk.
If you have more questions about it, then either keep asking here or maybe in the Discord server, which may be faster.
1 Like
Sorry replying late. And thanks for the resource, I will check and ask if I have more questions. Appreciate your advice and assistance!