You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I found a way to implement arbitrary coercion between types by using an infinite loop that type checks as a WellFounded relation.
Steps to Reproduce
» idris -v
1.3.1
||| WellFoundedLoop.idr
%defaulttotaldataFreeAccessible: {a:Type} -> (x:a) -> (y:a) ->TypewhereFreeAccess: {a:Type} -> {x:a} -> {y:a}
->AccessibleFreeAccessible x
->FreeAccessible x y
implementation WellFounded (FreeAccessible {a}) where
wellFounded x =Access (\y, (FreeAccess {x} {y} access') => access')
freeAccess: {a:Type} -> (x:a) -> (y:a) -> FreeAccessible {a} x y
freeAccess x y =FreeAccess {x} {y} (wellFounded x)
freeRec: {a:Type} -> (step : (x : a) -> ((y : a) -> b) -> b) -> a -> b
freeRec step =
wfRec {rel=FreeAccessible} (\x, f => step x (\y => f y (freeAccess y x)))
coerce: {a:Type} -> {b:Type} -> a -> b
coerce = freeRec (\x, f => f x)
main:IO()
main = coerce ()
%defaulttotal||| Isomorphic to: `(a:Type) -> a -> a -> a -> ..`dataFoo: (a:Type) ->TypewhereMkFoo: (a -> Foo a) -> Foo a
||| `f` is derived to be smaller than `MkFoo f`accFoo: {a:Type} -> {b:Type} -> a -> Foo a -> b
accFoo x (MkFoo f) = accFoo x (f x)
||| `Bar` is isomorphic to `Foo Bar`dataBar:TypewhereMkBar: Foo Bar -> Bar
runBar: Bar -> Foo Bar
runBar (MkBar fooBar) = fooBar
fooBar: Foo Bar
fooBar =MkFoo runBar
bar: Bar
bar =MkBar fooBar
accBar: {a:Type} -> a
accBar = accFoo bar fooBar
The totality checker detects that certain variants of Foo are not strictly positive as expected:
dataCoFoo: (a:Type) ->TypewhereMkCoFoo: (CoFoo a -> a) -> CoFoo a
dataEndoFoo: (a:Type) ->TypewhereMkEndoFoo: (EndoFoo a -> EndoFoo a) -> EndoFoo a
But the following variant allows us to define barId, which causes the type-checker to enter an infinite loop and leak memory:
dataFooId: (a:Type) ->TypewhereMkFooId: (a -> a) -> FooId a
runFooId: FooId a -> a -> a
runFooId (MkFooId f) = f
||| `BarId` is isomorphic to `BarId -> BarId`dataBarId:TypewhereMkBarId: FooId BarId -> BarId
runBarId: BarId -> FooId BarId
runBarId (MkBarId f) = f
fixBarId: (BarId -> BarId) -> BarId
fixBarId f = f (MkBar (MkFoo f))
barId: BarId
barId = fixBarId (\b => fixBarId (runFooId (runBarId b)))
I'm not sure BarId is the same bug: should I move it to another issue?
I found a way to implement arbitrary coercion between types by using an infinite loop that type checks as a
WellFounded
relation.Steps to Reproduce
To build:
Expected Behavior
The module should neither type check nor compile.
Observed Behavior
The text was updated successfully, but these errors were encountered: