I just realized that typed racket seems to ignore the guard anyway, so I could 
do something like this and convince the type-checker that any value I want has 
any type that I want:

(struct (a) foo ([a : a])
  #:guard (lambda (a _) "this value"))

(: x : (foo 1))
(define x (foo 1))

> (foo-a x)
- : Integer [more precisely: One]
"this value”


On Sep 28, 2014, at 10:41 PM, Benjamin Greenman <bl...@cornell.edu> wrote:

> I was able to get something very similar to your example program to compile.
> 
> (struct (a) foo ([a : a]) #:transparent 
>         #:guard (lambda (a _)
>                   (define a* a)  ;; a* not "polluted" by occurrence typing
>                   (unless (exact-integer? a) 
>                     (error 'foo "expected Integer, given ~v" a)) 
>                   a*))  ;; we return a value of type a, so the typechecker is 
> happy
> 
> From here, you can safely cast a foo-a into an Integer. It's not type safe to 
> ann because we (deliberately) don't have the occurrence typing information, 
> but we the programmers can be sure that the casts will never fail.
> 
> (cast (foo (ann 1 Any)) (foo Integer))
> > (foo 1)
> 
> 
> 
> On Sun, Sep 28, 2014 at 10:29 PM, Matthias Felleisen <matth...@ccs.neu.edu> 
> wrote:
> 
> You might be able to unwrap such things for a local context, but then you 
> need to wrap it again on the way out. That cost might become quite high if it 
> happens in a loop. Then again Racket programs rely on this a lot too (as do 
> many dynamically typed programs) so it might not be a cost that kills 
> performance completely. But do be aware of how others deal with this issue -- 
> Matthias
> 
> 
> 
> 
> 
> 
> 
> On Sep 28, 2014, at 10:03 PM, Alexander D. Knauth wrote:
> 
>> 
>> 
>> On Sep 28, 2014, at 8:25 PM, Matthias Felleisen <matth...@ccs.neu.edu> wrote:
>> 
>>>     
>>> Your message points out where gradual typing badly fails. 
>>> 
>>> Type systems combine two nearly orthogonal ideas: (1) proving theorems 
>>> about your program and (2) bridging the gap between abstract linguistic 
>>> constructs and concrete machine implementations. In a sense, the design of 
>>> a type system should always have the goal to eliminate as much run-time 
>>> overhead as possible. 
>>> 
>>> In this specific case, you have two aspects of dimensionality: dimension 
>>> per se (I am sure there is a word for it) and the chosen unit to represent 
>>> it. So if you know that a number denotes a distance, you can choose mm, m, 
>>> and km to represent it. If you want to represent an area, you choose mm^2, 
>>> m^2, km^2. Now if you want to compute the area of a rectangle, you write
>>> 
>>>  area-of-rectangle :  Real [Distance in m] * Real [Distance in m] -> Real 
>>> [Area in m^2]  
>>> 
>>> If someone writes (area-of-rectangle 1 [mm] 1 [km]), there is nothing wrong 
>>> with it -- except that the type checker should insert a coercion from mm to 
>>> m and from km to m (multiplying/dividing by 1,000). That is, a type system 
>>> for this application ought to use the type elaboration process idea and 
>>> translate code as it goes. 
>>> 
>>> This is quite comparable to the idea that a machine-oriented type system 
>>> needs to insert a coercion from integer to real (for example) as Algol 60 
>>> and its degraded successors do. 
>> 
>> What I had in mind was for the structs to be available at run-time, but that 
>> ideally the optimizer could take them out for the intermediate operations 
>> and put them back for the final result.  
>> 
>> And then if this value goes into untyped code, then it knows at run-time 
>> that it has the unit (u* millimeter kilometer), which is unit=? to 
>> square-meter.  
>> 
>> Is this sort of like what happens with flonum unboxing?  
>> 
>> 
>> 
>>> 
>>> Our gradual type system lacks some (intensiona) expressive power, which is 
>>> why you can't get close to this ideal. 
>>> 
>>> -- Matthias
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> 
>>> On Sep 28, 2014, at 8:14 PM, Alexander D. Knauth wrote:
>>> 
>>>> Yes I do want run-time residual of the dimensions, and yes I want a unit 
>>>> struct.  
>>>> 
>>>> Also if there’s run-time residual, then I can use predicates and 
>>>> occurrence typing, and it can also be used in untyped code with contracts 
>>>> instead of types.  
>>>> 
>>>> And also the type-checker would check if it is dimension-correct, but at 
>>>> run-time it would would still convert between different units of the same 
>>>> dimension, multiply and divide units, etc.  
>>>> 
>>>> On Sep 28, 2014, at 6:58 PM, Matthias Felleisen <matth...@ccs.neu.edu> 
>>>> wrote:
>>>> 
>>>>> 
>>>>> If you want the type checker to ensure your program is unit-correct, I 
>>>>> assume you also want no run-time residual of the dimensions but that is 
>>>>> in conflict with wanting a structure because it imposes a run-time cost. 
>>>>> Are you sure you want a unit? -- Matthias
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> 
>>>>> On Sep 28, 2014, at 1:37 PM, Alexander D. Knauth wrote:
>>>>> 
>>>>>> No because I want the unit to be a struct that has a dimension field, 
>>>>>> not a symbol with various dimensions defined as unions of units.
>>>>>> I want the unit to be based on the dimension, not the other way around, 
>>>>>> so that new units can be made that have the same dimension.
>>>>>> 
>>>>>> I have something like the number+unit struct (I called it measure), but 
>>>>>> I’ll work on more that after I have the unit struct figured out.  
>>>>>> 
>>>>>> On Sep 28, 2014, at 12:13 PM, Spencer florence 
>>>>>> <spencerflore...@gmail.com> wrote:
>>>>>> 
>>>>>>> would something like this work?
>>>>>>> 
>>>>>>> #lang typed/racket
>>>>>>> 
>>>>>>> (struct (U) number+unit ([amount : Real] [unit : U]))
>>>>>>> 
>>>>>>> (define-type Weight-Unit (U 'kg 'g 'mg 'μg))
>>>>>>> (define-type Weight (number+unit Weight-Unit))
>>>>>>> (define-predicate weight? Weight)
>>>>>>> 
>>>>>>> (: make-weight : Real Weight-Unit -> Weight)
>>>>>>> (define (make-weight n u)
>>>>>>>   (number+unit n u))
>>>>>>> 
>>>>>>> (: +/weight : Weight Weight -> Weight)
>>>>>>> ;; something something needs unit conversion
>>>>>>> (define (+/weight w1 w2)
>>>>>>>   (number+unit (+ (number+unit-amount w1)
>>>>>>>                   (number+unit-amount w1))
>>>>>>>                (number+unit-unit w1)))
>>>>>>> 
>>>>>>> (+/weight (make-weight 1 'kg) (make-weight 1 'kg))
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> On Sun, Sep 28, 2014 at 11:03 AM, Alexander D. Knauth 
>>>>>>> <alexan...@knauth.org> wrote:
>>>>>>> 
>>>>>>> Because the struct is representing a unit (kilograms, meters, seconds, 
>>>>>>> etc.), and a unit has a dimension (mass, length, time, etc.) and I want 
>>>>>>> the type-checker to be able to know what the dimension of a unit is so 
>>>>>>> that the types of functions can specify the dimension that something 
>>>>>>> should have. 
>>>>>>> The real solution to this would probably be bounded polymorphism, but I 
>>>>>>> was wondering if there was some other way to do it with occurrence 
>>>>>>> typing in the guard or something like that. 
>>>>>>> 
>>>>>>> On Sep 28, 2014, at 11:48 AM, Sam Tobin-Hochstadt 
>>>>>>> <sa...@cs.indiana.edu> wrote: 
>>>>>>> 
>>>>>>> > Why not do this with the type, instead of making this polymorphic? 
>>>>>>> > 
>>>>>>> > Sam 
>>>>>>> > 
>>>>>>> > On Fri, Sep 26, 2014 at 7:35 PM, Alexander D. Knauth 
>>>>>>> > <alexan...@knauth.org> wrote: 
>>>>>>> >> Is it possible to have a struct that does certain things according 
>>>>>>> >> to the 
>>>>>>> >> guard? 
>>>>>>> >> #lang typed/racket 
>>>>>>> >> 
>>>>>>> >> (struct (a) foo ([a : a]) #:transparent 
>>>>>>> >> #:guard (lambda (a _) 
>>>>>>> >> (unless (exact-integer? a) 
>>>>>>> >> (error 'foo "expected Integer, given ~v" a)) 
>>>>>>> >> a)) 
>>>>>>> >> 
>>>>>>> >> (ann (foo (ann 1 Any)) (foo Integer)) 
>>>>>>> >> 
>>>>>>> >> (: x : (foo Any)) 
>>>>>>> >> (define x (foo 1)) 
>>>>>>> >> 
>>>>>>> >> (ann (foo-a x) Integer) 
>>>>>>> >> 
>>>>>>> >> ;. Type Checker: Polymorphic function `foo1' could not be applied to 
>>>>>>> >> arguments: 
>>>>>>> >> ;Argument 1: 
>>>>>>> >> ; Expected: a 
>>>>>>> >> ; Given: Any 
>>>>>>> >> ; 
>>>>>>> >> ;Result type: (foo a) 
>>>>>>> >> ;Expected result: (foo Integer) 
>>>>>>> >> ; in: (foo (ann 1 Any)) 
>>>>>>> >> ;. Type Checker: Polymorphic function `foo-a' could not be applied 
>>>>>>> >> to 
>>>>>>> >> arguments: 
>>>>>>> >> ;Argument 1: 
>>>>>>> >> ; Expected: (foo a) 
>>>>>>> >> ; Given: (foo Any) 
>>>>>>> >> ; 
>>>>>>> >> ;Result type: (a : ....) 
>>>>>>> >> ;Expected result: Integer 
>>>>>>> >> ; in: (foo-a x) 
>>>>>>> >> 
>>>>>>> >> On Sep 25, 2014, at 9:42 PM, Alexander D. Knauth 
>>>>>>> >> <alexan...@knauth.org> 
>>>>>>> >> wrote: 
>>>>>>> >> 
>>>>>>> >> What I’m trying to accomplish is something more like this: 
>>>>>>> >> #lang typed/racket 
>>>>>>> >> 
>>>>>>> >> (require "dimensions.rkt") 
>>>>>>> >> 
>>>>>>> >> (struct (d) unit ([name : Any] [scalar : Positive-Real] [dimension : 
>>>>>>> >> d]) 
>>>>>>> >> #:transparent 
>>>>>>> >> #:guard (lambda (name scalar dimension _) 
>>>>>>> >> (unless (dimension? dimension) 
>>>>>>> >> (error 'unit "expected Dimension, given ~v" dimension)) 
>>>>>>> >> (values name scalar dimension))) 
>>>>>>> >> 
>>>>>>> >> (define-type (Unitof d) (unit d)) 
>>>>>>> >> 
>>>>>>> >> (define-type Unit (Unitof Dimension)) 
>>>>>>> >> 
>>>>>>> >> (define Unit? (make-predicate Unit)) 
>>>>>>> >> 
>>>>>>> >> (define-type Unitish 
>>>>>>> >> (U (Unitof Any) 
>>>>>>> >> Dimension 
>>>>>>> >> Positive-Real)) 
>>>>>>> >> 
>>>>>>> >> (: ->unit : (All (d) (case-> [(Unitof d) -> (Unitof d)] 
>>>>>>> >> [Unitish -> Unit]))) 
>>>>>>> >> (define (->unit u) 
>>>>>>> >> (cond [(unit? u) 
>>>>>>> >> (unless (Unit? u) ; this should never happen anyway because of the 
>>>>>>> >> guard 
>>>>>>> >> (error '->unit "expected (Unitof Dimension), given ~v" u)) 
>>>>>>> >> u] 
>>>>>>> >> [(dimension? u) (unit u 1 u)] 
>>>>>>> >> [(positive-real? u) (unit u u dimensionless-dimension)])) 
>>>>>>> >> 
>>>>>>> >> 
>>>>>>> >> On Sep 25, 2014, at 6:19 PM, Sam Tobin-Hochstadt 
>>>>>>> >> <sa...@cs.indiana.edu> 
>>>>>>> >> wrote: 
>>>>>>> >> 
>>>>>>> >> No, I don't think you can do this. Can you say more about what 
>>>>>>> >> you're 
>>>>>>> >> trying to accomplish? 
>>>>>>> >> 
>>>>>>> >> Sam 
>>>>>>> >> 
>>>>>>> >> On Thu, Sep 25, 2014 at 6:15 PM, Alexander D. Knauth 
>>>>>>> >> <alexan...@knauth.org> wrote: 
>>>>>>> >> 
>>>>>>> >> Do any of you have any advice for getting a function like this to 
>>>>>>> >> type-check? 
>>>>>>> >> #lang typed/racket 
>>>>>>> >> 
>>>>>>> >> (: check-int : (All (a) (case-> [a -> a] 
>>>>>>> >> [Any -> Integer]))) 
>>>>>>> >> (define (check-int int) 
>>>>>>> >> (unless (exact-integer? int) 
>>>>>>> >> (error 'check-int "expected Integer, given ~v" int)) 
>>>>>>> >> int) 
>>>>>>> >> 
>>>>>>> >> ;. Type Checker: type mismatch 
>>>>>>> >> ; expected: a 
>>>>>>> >> ; given: Integer in: int 
>>>>>>> >> 
>>>>>>> >> 
>>>>>>> >> 
>>>>>>> >> ____________________ 
>>>>>>> >> Racket Users list: 
>>>>>>> >> http://lists.racket-lang.org/users 
>>>>>>> >> 
>>>>>>> >> 
>>>>>>> >> ____________________ 
>>>>>>> >> Racket Users list: 
>>>>>>> >> http://lists.racket-lang.org/users 
>>>>>>> >> 
>>>>>>> >> 
>>>>>>> 
>>>>>>> 
>>>>>>> ____________________ 
>>>>>>> Racket Users list: 
>>>>>>> http://lists.racket-lang.org/users 
>>>>>>> 
>>>>>>> 
>>>>>> 
>>>>>> ____________________
>>>>>>  Racket Users list:
>>>>>>  http://lists.racket-lang.org/users
>>>>> 
>>>> 
>>> 
>> 
> 
> 

____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to