New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A somewhat radical proposal for Show #1675
Comments
I like it. I think a conversion to I'm not so sure converting-anything-to- edit: rather, conversion-to-printable-value, perhaps |
Maybe just creating a record would be a enough? Suppose you want to print
Or even
|
That's true, or event just provide a |
I've recently come across an instance where it would be useful to get the It's just a bit unfortunate that having a |
Oh wait, no, you don't need to convert to Although this specific use case does reveal another thing: if we had a |
I like your proposal. But what if I really want to convert a value to a |
We would add extra functions for those things, I guess. I would argue that they should be monomorphic. |
A big 👍 from me on this. It would be nice if @sharkdp a class ToString a where
toString :: a -> Maybe String -- not all things can be converted This is total and goes nicely with the reverse too: class ParseFromString a where
fromString :: String -> Maybe a But using a specific serialisation format (like JSON or Transit or whatever) might be better suited for your use case. You can also create type classes for that. The problem with |
Perhaps the way to implement this is to have move |
👍. Rust called theirs |
I was going to suggest the same thing 😄 |
Hah, that would have been my suggestion too. |
I hope this is related: it seems impossible to log/trace/debug an object that doesn't have a Show. As a newbie to PureScript (but not programming), I just want to be able to show a result to make sure things are working, but I can't because it doesn't have a Show. It's killing me. In JavaScript, I can "console.log({ anything: true })" and it works, but I can't do that in PureScript. |
@greglearns You can do this currently, see: https://pursuit.purescript.org/packages/purescript-console/0.1.1/docs/Control.Monad.Eff.Console.Unsafe#v:logAny |
Thank you! |
@greglearns I also use |
@jonsterling even better! thanks!
|
@greglearns I think I can't tell where the conversation ended up but I'd prefer the browser's rendering to a vanilla |
That's a good point. I guess we would need to allow user defined instances for types like Map and Set somehow. |
Another 👍 . Not being able to print values is often a big hangup for me, especially when I try to demo something live to a co-worker. I like the |
I think the debug
|
The issue with automatically looking up debuggable :: Debug a => a -> a
debuggable a = debug a a What should the compiler generate there? It doesn't have enough type structure available to generate anything useful. |
@paf31 Sorry, I don't quite understand what the problem is there. Can we not generate the same code here that we would for a normal typeclass there? Since @AppShipIt pointed out that some types (eg, |
So what's the condition for when we solve vs. derive? When the type is fully instantiated? Sometimes we need a combination of the two: data Foo a = Foo a
debuggable :: Debug a => Foo a -> Foo a
debuggable a = debug a a When the compiler sees this, it needs to know to reduce |
I've been thinking about this a bit more, and I think we can reduce the magicalness of my original proposal a bit and still retain usefulness. Instead of automatically deriving instances, I think it might be better to use the existing typeclass deriving mechanic where you have to ask for an instance by writing a Here's a concrete proposal for what could be added to data Any :: Type
toAny :: forall a. a -> Any
data Debugged
= Debugged String (Array Debugged)
-- I'll explain this constructor in a moment
| DebuggedAsIs Any String (Array Debugged)
class Debug a where
toDebugged :: a -> Debugged As @rightfold notes, we could then do handy things like putting parens in the right place, or printing to So for example we might define: -- hopefully this is what the derived instance would look like
instance debugMaybe :: Debug a => Debug (Maybe a) where
toDebugged (Just a) = Debugged "Just" [debug a]
toDebugged Nothing = Debugged "Nothing" []
-- but this would need to be hand-written
instance debugMap :: (Debug k, Debug v) => Debug (Map k v) where
toDebugged = Debugged "Map.fromFoldable" <<< Array.singleton <<< toUnfoldable Where the The reason for having the Then for types that browsers are aware of, we would define instances which use the instance debugNumber :: Debug Number where
toDebugged x = DebuggedAsIs x "Number" []
instant debugArray :: Debug a => Debug (Array a) where
toDebugged xs = DebuggedAsIs xs "Array" (map debug xs) On the magicalness front, I think it might be better not to try to give One issue I foresee is that if you're trying to debug polymorphic code, you might have to put a whole bunch of We would also want to define a One thing I'm not sure about: is it feasible to define a |
@hdgarrood This isn't a full reply, but remember that we can't put functions, data types or classes with member functions into |
Ah of course. Could we put it in |
It wouldn't need to be in Prelude necessarily, but that would be preferable. As long as it's in core somewhere, I think we could derive it in the compiler. I'd also be fine with deriving |
What about just solving Edit: we could even generate a warning telling the user that they used a generated |
I think that would be good, but I do worry that |
Having RowToList and Warn changes this quite drastically: I actually don't think we need much magic at all to achieve this now. I'm attempting to do as much as I can in "userland" now. I'm going to close this for now; maybe I'll reopen once I've made some progress. Edit: if you want to see what I've done, I've made a start at https://github.com/hdgarrood/purescript-debugged. |
(Vaguely related to purescript/purescript-prelude#46.)
I think @jonsterling is on to something here (I recommend reading at least the first few replies as well): https://twitter.com/jonsterling/status/670091766549344257
I've felt vaguely uneasy about the Show type class for a long time and I think this hits the nail on the head. I think our current Show type class is unsuitable for debugging / use in the REPL (which ought to be its main aim) because:
Show
instance, for example,(->)
. This doesn't seem so bad, because what use wouldshow
ing a function be anyway? But it can be irritating when you want to print larger structures which contain types like(->)
. In particular, at the moment, you can't useGeneric
; you have to write outShow
instances which skip over the "unshowable" things yourself.String
, it's just too tempting to abuse it for serialization (as we have discovered in the Haskell community).Show
instances, the more dangerousshow
becomes; given that it works on almost anything, and that the return type is justString
(rather than something that mentions the input type likepure
, for example) it's very easy to callshow
on the wrong thing. It's almost like using a dynamic language!@jonsterling suggests having
print :: forall a. a -> Unit
instead, similar to the existing purescript-debug library.I think we could improve this situation significantly by having a compiler-supported Show replacement.
I propose that we add a type class to the compiler. Let's call it
Debug
(it wouldn't depend onpurescript-foreign
, this is just to illustrate):Where the return type of
debugShow
is anything that is suitable to be passed toconsole.log
. Sometimes this will just be a String, but often I think it's a good idea to leave other types as they are, as browsers can offer nicer UIs. Tryconsole.log({foo: 1})
in Firefox or Chrome for instance.This type class would be invisible to the user, if possible, but we also provide a function which is visible, something like
print :: forall a. (Debug a) => a -> Unit
, or perhaps closer to the types inpurescript-debug
, and which internally doesconsole.log <<< debugShow
before returningunit
.We add a special case in the compiler so that every type is an instance of
Debug
, including functions and records. Defining your own instances is not allowed. This way, we don't need to worry about orphans and all that (I think).These instances would probably do something like:
debugShow
on each.map debugShow
.data
ornewtype
), do the same thing as the what the derivedShow
instance in Haskell would do.foreign import data
could probably be left alone.print id
might produce"<Function: forall a. a -> a>"
.and so on.
If
print
occurs in your program, it generates a compiler warning, which helps you avoid accidentally leaving them in.print
could also include the current file name and line number.I realise this is, to some extent, at odds with the current minimalistic approach of the compiler. But to me, it appears promising enough to justify bending the rules a little. And I think it would allow us to get rid of Show. This would not only make me happy not only because Show unnerves me, but also because it would take us most of the way to removing all the runtime dependencies of
psci
— If we also moved theEff
type intoPrim
then$PSCI.Support
could have no library dependencies, which would resolve #1441.The text was updated successfully, but these errors were encountered: