Is there a way to build the implementation of an interface "dynamically"?
I have some code which looks like
record MySemigroup where
constructor MkMySemigroup
set : Type
op : set -> set -> set
mySemigroupIsSemigroup : (s : MySemigroup) -> Semigroup (set s)
mySemigroupIsSemigroup s = ?hole
and I would like to define the instance of Semigroup on set s using op s.
Related
I am trying to do some category theory in Lean. However, I am not yet very fluent in type theory, and the following does not really seem to work:
class pset (S: Type) :=
(point: S)
class category (𝒞: Type) :=
(test: unit)
instance pset_category : category pset :=
{
test := ()
}
I get a type mismatch at category pset, since pset has type Type -> Type, whereas it is expected to have type Type. What is going wrong?
I assume you want pset to be something like "pointed sets". So then its definition should be
class pset :=
(S : Type)
(point : S)
Now you will notice that #check pset tells you it has type Type 1. So you still can't make it into a category, since you only defined "small" categories. If you change Type to Type* in the definition of category, all should be good.
I am playing a bit with F# interfaces, by creating a simple data access class.
The interface is:
type IUserAccess =
abstract member GetUsers : (dbSchema.ServiceTypes.Users -> bool) -> dbSchema.ServiceTypes.Users seq
abstract member GetAllUsers : unit -> dbSchema.ServiceTypes.Users seq
In the class, I am calling the methods in this way:
type UserAccess() =
let db = dbSchema.GetDataContext()
interface IUserAccess with
member this.GetUsers cond =
let query = query {
for row in db.Users do
select row }
query |> Seq.where cond
member this.GetAllUsers () =
(this:>IUserAccess).GetUsers (fun _ -> true)
What I'm a bit concerned with is the way I am calling GetAllUsers function, specifically with part (this:>IUserAccess). What is the simplest way of calling methods that are implemented within the same interface?
One simple option I can think of is creating GetUsers method directly within UserAccess() class and then calling it from the interface implementation of both GetUsers and GetAllUsers, but that means a new private method implemented, which I would like to avoid. Is there another option?
I think the solution by #vcsjones is probably the best option if you want to avoid defining a separate method directly inside the class. That said, declaring a separate method is actually not that ugly. You can use local definition using let binding (which is automatically compiled as a private method) and I think it makes the code look quite nice:
type UserAccess() =
let db = dbSchema.GetDataContext()
let getUsers cond =
let query = query {
for row in db.Users do
select row }
query |> Seq.where cond
interface IUserAccess with
member this.GetUsers cond = getUsers cond
member this.GetAllUsers () = getUsers (fun _ -> true)
I generally quite like this style, because it separates all the private implementation from the part of the definition where you're defining the public exposed API.
F# always implements interfaces explicitly, so your options are pretty much as you stated, but you can avoid redundant casting by introducing a let binding:
type IUserAccess =
interface
abstract member GetUsers : (obj -> bool) -> unit
abstract member GetAllUsers : unit -> unit
end
type Foo() as self =
let userAccess = self :> IUserAccess
interface IUserAccess with
member this.GetUsers(q : (obj -> bool)) : unit =
()
member this.GetAllUsers() =
userAccess.GetUsers(fun _ -> true)
I just simplified your interface and object so I could get something compiling real quick.
I am really confused about classes in haskell. If I had the code:
class GetResult n where res :: n -> Int
class (GetResult n) => Model n where
starting :: Int -> [Int] -> n
starting i j = .....
test :: n -> n
test n = ......
What type is n? What type would starting output and test take as input?
Your confusion might be caused by the fact that type classes in Haskell have nothing to do with classes in OO. Most importantly type classes don't describe objects, they describe types.
A type class describes a set of methods. You can implement those methods for a given type to make that type an instance of the class. So your type class definition of GetResult can be read as "A type n can be made an instance of GetResult by implementing the method res of type n -> Int". So n is simply the type that wants to become an instance of GetResult.
As an example if you wanted to make Int an instance of GetResult, you could use the following instance declaration:
instance GetResult Int where
res :: Int -> Int
res i = i
In this case n would be Int.
n is a type variable, not any particular type. Particular types can be made instances of GetResult and Model, and each instance will "fill in the blanks" in the types of the functions defined in the class.
So the full type of starting is (you can get this from ghci with :t starting):
starting :: Model n => Int -> [Int] -> n
You can read this as "for any type which is an instance of Model, starting takes an Int and a [Int] and returns a value of that type". Likewise test takes any type which is an instance of Model and returns a value of the same type.
At any particular call of starting, the type returned will be determined by the context; it will return a value of whatever type its return value is used as in that context (assuming a suitable instance exists).
Given the generic register method below I would like to define the := operator as a symbolic alias.
def register[Prop <: Property[_]](prop: Prop): Prop
#inline
final def :=[Prop <: Property[_]] = register[Prop] _
Originally I wanted to write something like this:
val := = register _
But that gives me the function signature Nothing => Nothing. My next attempt was to parameterize it with the type Prop but that apparently works only if I make it a def, which can take type parameters and pass them onwards.
Ideally I would like to omit the #inline annotation but I am not sure what object code the Scala compiler makes out of it.
Most important my goal is it not to have the := method duplicate all parts of the register method's signature except for the name and then simply let the former delegate to the latter.
def :=[Prop <: Property[_]](prop: Prop) = register(prop)
should work.
I don't believe that there's any way to achieve what you're after (basically what alias gives you in Ruby) in Scala as it currently stands. The autoproxy plugin is an attempt to address this kind of problem, but it's not really ready for production use yet due to various issues with generating code in compiler plugins.
You can do this:
def := : Prop => Prop = register
So basically here you define a function of type (Prop => Prop) that just references another function.
In (very) modern GHC's, I can write this:
{-# LANGUAGE TypeFamilies #-}
-- consider this part "library" code, changeable at will
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Element ~ a => Foo (Container a) where foo _ = 0
-- consider this part "client" code; bonus points if it can remain exactly as is
main = print (foo Container)
Salient points:
The client code did not require any additional type signatures.
Container, which is a polymorphic value (of type Container a), was correctly monomorphed to Container Element.
No newtype wrappers were required in the client code.
It is probably not possible to declare another instance of Foo whose outermost type constructor is Container. This is not a property I care about preserving in the following discussion.
Can this be done in a more backwards-compatible way? My first attempt looked like this:
{-# LANGUAGE FlexibleInstances #-}
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Foo (Container Element) where foo _ = 0
main = print (foo Container)
...which gives an error:
test.hs:8:15:
No instance for (Foo (Container a0))
arising from a use of `foo'
Possible fix: add an instance declaration for (Foo (Container a0))
In the first argument of `print', namely `(foo Container)'
In the expression: print (foo Container)
In an equation for `main': main = print (foo Container)
I realized that this error probably arises because the instance doesn't use a type variable as the argument to Container, so I also tried:
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Convertible a Element => Foo (Container a) where foo _ = 0
class Convertible a b where
-- convert is not necessary in this tiny example, but it would
-- be necessary in my not-so-tiny use case
convert :: Container a -> Container b
instance Convertible a a where
convert = id
main = print (foo Container)
But this just pushes the problem to the Convertible type class:
test.hs:14:19:
No instance for (Convertible a0 Element)
arising from a use of `foo'
Possible fix:
add an instance declaration for (Convertible a0 Element)
In the first argument of `print', namely `(foo Container)'
In the expression: print (foo Container)
In an equation for `main': main = print (foo Container)
A similar error arises from writing an instance for Convertible Element Element instead of Convertible a a. My last-ditch attempt was to specialize even further:
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance IsElement a => Foo (Container a) where foo _ = 0
class IsElement a where
convert :: a -> Element
instance IsElement Element where
convert = id
main = print (foo Container)
...which has the notable benefit of being H98, but the notable downside of still not quite working:
test.hs:10:19:
Ambiguous type variable `a0' in the constraint:
(IsElement a0) arising from a use of `foo'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `print', namely `(foo Container)'
In the expression: print (foo Container)
In an equation for `main': main = print (foo Container)
So, the question is this: is there some similar implementation that achieves properties 1, 2, and 3 above, yet does not require the type equality operator?
edit I thought rank-2 types might help:
{-# LANGUAGE FlexibleInstances, RankNTypes #-}
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Foo (forall a. Container a) where foo _ = 0
main = print (foo Container)
...but alas, still no dice:
test.hs:6:14:
Illegal polymorphic or qualified type: forall a. Container a
In the instance declaration for `Foo (forall a. Container a)'
I don't understand what you're trying to do here. In particular, why do you care that Container is polymorphic when you only want the client to work with Container Element?
That said, how about using a different kind for the type class?
data Container a = Container
data Element
class Foo a where foo :: a x -> Int
instance Foo Container where foo _ = 0
Now it truly doesn't matter which type Container is instantiated to.
If this doesn't work, I suspect the answer is "no, you can't do precisely what you want." Although you could export container = Container :: Container Element and have client code use that instead of Container.
Edit: given the full context, and that rank-2 types aren't possible either, I am reasonably certain that there isn't a solution given the problem constraints. The best workaround I can think of is creating a new function xcast :: XConfig a -> XConfig Layout. This would allow you to write instance Binding (XConfig a -> Foo).