Giter VIP home page Giter VIP logo

Comments (14)

jiegillet avatar jiegillet commented on June 15, 2024

I'm happy to tackle this too after #106 is settled maybe.
I'm assuming:

  • Set, HashSet <=> TArray
  • ByteString <=> TText
  • Natural, Word <=> TInteger
  • Float <=> TDouble

from tomland.

chshersh avatar chshersh commented on June 15, 2024

@jiegillet You're very close to the truth!

Natural, Word <=> TInteger
Float <=> TDouble

The above combinators are fine 👍

ByteString <=> TText

The types are true. But this should be done carefully since not every ByteString can be converted to Text.

Set, HashSet <=> TArray

Probably, should wait for this one. Currently we don't even have combinator for the list. After we have list, we can implement Set and HashSet trivially.

from tomland.

jiegillet avatar jiegillet commented on June 15, 2024

Got it. I'll be careful with the ByteString and I'll think about lists for a bit.

from tomland.

jiegillet avatar jiegillet commented on June 15, 2024

I've thought for a bit, and (sorry) my typeclass idea showed up again.
Here is what I have in mind

class Valuable a where
  toValue :: a -> Maybe AnyValue
  matchValue :: AnyValue -> Maybe a

  _Valuable :: BiMap AnyValue a
  _Valuable = BiMap matchValue toValue

instance Valuable Bool where
  toValue = Just . AnyValue . Bool
  matchValue (AnyValue t) = matchBool t

instance (Valuable a) => Valuable [a] where
  toValue = mapM toValue >=> fmap AnyValue . toMArray
  matchValue (AnyValue v) = matchArray matchValue v

_Bool :: BiMap AnyValue Bool
_Bool = _Valuable

_List :: Valuable a => BiMap AnyValue [a]
_List = _Valuable

It compiles and I think it's very easy to read and write. What do you think?

BTW, I just want to say that toMArray has an awesome implementation, I was struggling to implement something like that before I realized it was already there.

EDIT:
And one helpful function

_BiMapVia :: Valuable m => (a -> Maybe m) -> (m -> Maybe a) -> BiMap AnyValue a
_BiMapVia toVal fromVal = _Valuable >>> BiMap fromVal toVal

from tomland.

chshersh avatar chshersh commented on June 15, 2024

@jiegillet In that case Valuable doesn't really decreases amount of work. You still write implementation for every conversion function, just put it into typeclass.

Re _BiMapVia: it's very rare case to have two functions with return values Maybe. So we end having several different combinators... But more importantly, you don't really need BiMapVia. Instead of passing two functions of types a -> Maybe m and m -> Maybe a you can just create BiMap a v and compose it with _Text or _Integer or any other terminal combinator.

One thing that is hard to write with typeclass-based solution is the following function:

_Value :: (a -> Value t) -> (Value t -> a) -> BiMap a (Value t)

With such function you can guarantee that tag t is the same in both directions. So the following won't typecheck:

_Value Integer fromText

It's hard to encode this with typeclasses if you have separate functions for converting in every direction.

BTW, I just want to say that toMArray has an awesome implementation, I was struggling to implement something like that before I realized it was already there

Thank you very much for the kind words ❤️ We decided to use GADTs in this library to introduce more typesafety to the internal types. But this involves some dependent-type programming and theorem proving, so some functions are a bit hard to write...

from tomland.

jiegillet avatar jiegillet commented on June 15, 2024

OK, I think I understand better, thank you for explaining again. I have barely used GADTs before, I can understand some code fine, but I don't have an intuition for what they do and cannot do versus compared to typeclasses.

I agree that it doesn't decrease the amount of work, but it does let you write _List easily :)

I guess we need to use _Array then (which I think should be renamed _List since we are giving names based on the concrete types BiMaps encode). I can use it to make _Set and _HashSet then, something like _Set :: BiMap a AnyValue -> BiMap (Set a) AnyValue.

from tomland.

chshersh avatar chshersh commented on June 15, 2024

I agree that it doesn't decrease the amount of work, but it does let you write _List easily :)

The problem with List currently is that it's not possible with tomland to encode list of custom user data types (and Set and HashSet as a consequence). With _Array you can only have list of primitive types (Int, Double, Text).

from tomland.

jiegillet avatar jiegillet commented on June 15, 2024

You can have more than (Int, Double, Text):

_ShowArray :: (Show a, Read a) => BiMap AnyValue [a]
_ShowArray = _Array _Show

It compiles fine.

from tomland.

jiegillet avatar jiegillet commented on June 15, 2024

I think _Set is not an issue:

_Set :: (Ord a) => BiMap AnyValue a -> BiMap AnyValue (S.Set a)
_Set bimap = _Array bimap >>> BiMap (Just . S.fromList) (Just . S.toList)

_ HashSet is more tricky

_HashMap :: (Eq k, Hashable k) => BiMap AnyValue (k, v) -> BiMap AnyValue (H.HashMap k v)
_HashMap bimap = _Array bimap >>> BiMap (Just . H.fromList) (Just . H.toList)

because we can't create BiMap AnyValue (k, v) easily. Unless we require Show k, Show v, Read k, Read v, then (k, v) can be inputed via _Show.

from tomland.

chshersh avatar chshersh commented on June 15, 2024

@jiegillet Yeah, delegating to Read and Show is a possible option. But it's very slow solution. And, in that case, why TOML and not just store Read/Show version of Haskell data structure in the file? 🙂

from tomland.

jiegillet avatar jiegillet commented on June 15, 2024

Agreed, it's a terrible solution.
Is there a way to do something like

data TValue = TBool | ... | TPair TValue TValue

data Value (t :: TValue) where
    Pair :: Value t1 -> Value t2 -> Value (TPair t1 t2)

Again. Very limited experience with GADTs, sorry if it's not possible.

EDIT: seems to work, I'm having trouble defining sameValue though. I'll keep thinking.

from tomland.

chshersh avatar chshersh commented on June 15, 2024

Is there a way to do something like

Yeah, it's possible, but usefulness of this definition is quite limitied. TValue and Value should represent exactly the TOML specification, and TOML doesn't have pairs. But it's definitely possible! sameValue for this case might be tricky, that's true.

from tomland.

jiegillet avatar jiegillet commented on June 15, 2024

After many experimentation I managed to do it (I know it's not useful for tomland it's just for fun at this point):

sameValue (Pair a1 b1) (Pair a2 b2) 
    = apply <$> (apply Refl <$> sameValue a1 a2) <*> sameValue b1 b2

The weakness is that if both values in the pair are mismatched, I only get one TypeMismatchError in the resulting Left. Anyway.

Oh my gosh, I realize now that I was supposed to implement _HashSet and I did _HashMap. My bad.

_HashSet :: (Eq a, Hashable a) => BiMap AnyValue a -> BiMap AnyValue (H.HashSet a)
_HashSet bimap = _Array bimap >>> BiMap (Just . H.fromList) (Just . H.toList)

One problem I realized by looking at the TOML specifications is that [["a", "b"], [1, 2]] is a valid TOML array, although it cannot be a valid Haskell list. Have you thought at what to do about that?

from tomland.

chshersh avatar chshersh commented on June 15, 2024

One problem I realized by looking at the TOML specifications is that [["a", "b"], [1, 2]] is a valid TOML array, although it cannot be a valid Haskell list. Have you thought at what to do about that?

Yes, I actually thought about that when I've implemented bidirectional conversion first time! You can see my thoughts here:

I still don't see good usage of such arrays in Haskell, but it may arise in future.

from tomland.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.