简体   繁体   中英

How do you present any data type to the user with PureScript?

I want to make a very human-friendly development environment, and I'm considering using PureScript to provide the language part. I see that out of the box, Show doesn't work on records of things which are instances of Show :

log (show {a:5})

The 'Try PureScript!' ( http://try.purescript.org/ ) compiler says:

   No type class instance was found for

   Prelude.Show { a :: Int
                }

Is there a tool for generically printing any data structure, especially one containing records? Is there some type trickery that would support generically walking over the record to support my own class like present :: Present a => a -> Presentation ? The problem is that I don't know what the types will be ahead of time. The user enters a record and I want to be able to present it. It seems that I'll have to patch the compiler to support this.

Records are disallowed in instance heads. For discussion and reasons, see this thread .They must be wrapped in data or newtype if we want to write instances for them.

However, there is a generics library and a deriving mechanism that lets us generate Show instances.

import Data.Generic

data Foo = Foo {a :: Int} | Bar {b :: String}
derive instance genericFoo :: Generic Foo

instance showFoo :: Show Foo where
   show = gShow

Working with untyped data in PureScript is done using the purescript-foreign or the purescript-argonaut libraries. I'd suggest argonaut.

The representation of a record with unknown fields and unknown types for these fields would be: StrMap Json from the purescript-maps package. I'd suggest you take a look at the (not yet merged) documentation over here: https://github.com/hdgarrood/purescript-argonaut-core/blob/565c7e650c51c45570663cf1838ec9cfa307a9c7/README.md . I've also put together a little example, showing how to match on a heterogeneous array from JavaScript:

-- src/Main.purs
module Main where

import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
import Data.Argonaut (foldJson, Json)
import Data.Foldable (traverse_)

newtype Presentation = Presentation String

unPresentation :: Presentation -> String
unPresentation (Presentation p) = p

instance showPresentation :: Show Presentation where
  show = unPresentation

class Present a where
  present :: a -> Presentation

instance presentInt :: Present Int where
  present = Presentation <<< show

instance presentNumber :: Present Number where
  present = Presentation <<< show

instance presentBoolean :: Present Boolean where
  present = Presentation <<< show

instance presentString :: Present String where
  present = Presentation

presentJson :: Json -> Presentation
presentJson =
  foldJson
    (const (Presentation "null"))
    present
    present
    present
    (const (Presentation "array"))
    (const (Presentation "record"))

foreign import vals :: Array Json

main :: forall e. Eff ( console :: CONSOLE | e) Unit
main = traverse_ (log <<< show <<< presentJson) vals

And the corresponding js file:

// src/Main.js
// module Main

exports.vals = [1, 1.2, "hello", true, [1,2,3], {a: 3, b: "hi"}];

Running this program gives you:

> pulp run
* Building project in/home/creek/Documents/so-christopher-done
* Build successful.
1.0
1.2
hello
true
array
record

Yes, traceAny and related functions from purescript-debug . Here are a few examples: test/Main.purs#L22 . I'd post the links to Pursuit, but it doesn't seem to have purescript-debug at the moment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM