Replies: 13 comments
-
|
This is a feature that is requested before (#56), and something we definitely want to implement. Having this amount of type-safety will really introduce a huge benefit over using C. Indeed With the limited time we can currently spent on developing Copilot, we focus mostly on bugfixing and cleaning the project up. Copilot's types are one of the things that we want to try to simplify, most likely aiding in implementing more strict types. |
Beta Was this translation helpful? Give feedback.
-
|
Although the approach is different, this issue is closely related to #56 and solving this one would solve that one too. i have closed #56, but it may actually be a good starting point and should be considered if some additional type safety feature is to be implemented. |
Beta Was this translation helpful? Give feedback.
-
|
I'm too noob to make any meaningful contribution in this space. How are you making up for the lack of Haskell types currently? It seems that Copilot programs currently are forced to use the C types defined in Type. Is there some way, for example, to (maybe unsafely) cast a Haskell Enum to a Word32? |
Beta Was this translation helpful? Give feedback.
-
|
Sorry, but wouldn't it be possible to do something like this? Where the binary class Then you could say that any type can be reduced to itself, and a new type would only need to define an instance saying that it can be reduced to the type it encloses? EDIT: |
Beta Was this translation helpful? Give feedback.
-
|
We may want to look into https://hackage.haskell.org/package/base-4.14.1.0/docs/Data-Coerce.html#t:Coercible. We might be able to provide instances for |
Beta Was this translation helpful? Give feedback.
-
|
By the way, I have no idea why we require the |
Beta Was this translation helpful? Give feedback.
-
|
I wasn't able to get the |
Beta Was this translation helpful? Give feedback.
-
|
Tagging @avieth . Maybe he knows. There may be a way to simplify his solution using |
Beta Was this translation helpful? Give feedback.
-
|
I think I've figured out a way that we can have both Enums, newtypes, any type (including a data) that wraps some other type, and any type that we can convert to a known type (e.g., a struct). Here's a prototype implementation: https://github.com/ivanperez-keera/copilot/tree/develop-multitypes It's incomplete, in that some instances are missing. There are things we can probably do better, and/or where we can use standard/existing classes, leverage the type system, etc. I'm very open to ideas. The following example compiles and produces (what I believe is) correct C code: {-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE MultiParamTypeClasses #-}
import GHC.Generics (Generic)
-- External imports
import Prelude hiding (all, mod, not, or, until, (&&), (++), (<), (<=), (==),
(>), (>=), (||))
-- Internal imports
import Copilot.Compile.C99
import Language.Copilot (reify)
import Language.Copilot hiding (all, or)
main :: IO ()
main = do
f <- reify spec
compile "c" f
spec :: Spec
spec = do
-- Enums. Automatically converted to int64
trigger "f" true [ arg streamOfAB ]
-- Newtype. Manually converted to inner type.
trigger "g" true [ arg streamOfMI ]
-- Data. Manually converted to a struct
trigger "h" true [ arg streamOfData ]
-- * Test with enums
data A = A | B
deriving (Eq, Enum, Show)
instance Typed A where
typeOf = Enum A
streamOfA :: Stream A
streamOfA = constant A
streamOfAB :: Stream A
streamOfAB = [A, B] ++ streamOfAB
-- * Test with newtypes
newtype MyInt = MyInt { u :: Int8 }
deriving (Eq, Show)
instance Wraps MyInt Int8 where
unwrap = u
instance Typed MyInt where
typeOf = Wrapper Int8
streamOfMI :: Stream MyInt
streamOfMI = constant (MyInt 8)
-- * Test with arbitrary datatypes
data MyType = MyType Int8 Bool
deriving (Eq, Show)
instance Typed MyType where
typeOf = Wrapper (Struct (MyTypeS (Field 0) (Field False)))
instance Wraps MyType MyTypeS where
unwrap (MyType x y) = MyTypeS (Field x) (Field y)
streamOfData :: Stream MyType
streamOfData = [ MyType 8 False, MyType 9 True ] ++ streamOfData
-- ** Actual representation of the type
-- | The type we will convert it to. We only need to do this once.
-- There may be a way to automate this.
data MyTypeS = MyTypeS
{ f1 :: Field "f1" Int8
, f2 :: Field "f2" Bool
}
deriving Generic
instance Struct MyTypeS where
typeName = typeNameDefault
toValues = toValuesDefault
instance Typed MyTypeS where
typeOf = typeOfDefaultThe example is included in the same branch as Tagging @RyanGlScott @fdedden @agoodloe for awareness. |
Beta Was this translation helpful? Give feedback.
-
|
It's possible that the mechanism for Also, I had to disable the instance of |
Beta Was this translation helpful? Give feedback.
-
|
A question I'd have at this point is what can one do with these streams. We'd need to give users access to the fields (in the case of records). Also, arbitrary records and enums cannot be used as externs. In the above, you'd need functions with types like |
Beta Was this translation helpful? Give feedback.
-
|
We might, in general, need projections and injections elevated to the language of streams, similarly to what we ended up needing for structs and arrays. |
Beta Was this translation helpful? Give feedback.
-
|
Just to make sure I understand, is the goal here is to develop a Copilot-level type
Is that correct? Here are some assorted thoughts about the prototype solution you've implemented:
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Motivation
It would be great to have domain-specific Haskell types in streams, as this can give extra type safety in the high-level model that, with correct code generation, holds true even in the less-strongly-typed target language. Take this simple example with three nominally and semantically distinct types with the same representation:
I've judged that this is not possible presently, simply because of the definition of
TypedTo get
Typed Time_ms, for example, you need to give aType Time_ms, but there is no such thing: it's not a struct or an array, it's aWord32, but the type parameter must beTime_ms.How could it be done
Needless to say, this would be a massively breaking change worthy of a new major version number.
The idea is to define a kind for types in the object language (Haskell being the meta language) and use this to parameterize Haskell types which represent the object language types and values of those types. The
Typedclass would then become (ignore bad choice of names)and we could get this for our example
Here's what
CType,CTypeRep, andCValRepcould be (as a bonus, we also get support union and enum types)Beta Was this translation helpful? Give feedback.
All reactions