Comments (4)
Since I stumbled upon this on my own, I don't know whether
it's recommended per se (some input on that front would be
appreciated), but it seems to work.
I would say solution 2 is the idiomatic way to do it. With the solution
number 1 you can still create two heaps in two different contexts
using two different notions of order and then merge them using a
third notion of order.
The only way to guarantee that users cannot possibly use the wrong
notion of order when manipulating your heaps is to add it as a
parameter.
In Haskell it's different because
- you cannot parametrise your data structures with an
Ord a
- it's not that big of a deal given that you are only supposed to
have one instance per type
from idris2.
Comment by edwinb
Tuesday Mar 17, 2020 at 21:14 GMT
The error message is bad, but there are definitely two possible results: one from the first Node, one from the second. There's no guarantee they'd be the same.
from idris2.
I've run into a similar issue and I've found a couple different solutions, neither of which involve compiler bugs (so I think this issue can be closed).
As edwinb said, there are genuinely two different Ord
implementations in scope there. You might think "but it should know that they're both the same", but there's no reason that they must be: one of those Heap
s could have been created in another context where the compiler selected a custom Ord elem
implementation.
There are two potential solutions to this:
- Stop trying to enforce the constraint in the data constructors (where it isn't necessary) and instead add the constraint only to functions which act on
Heap
. - Making it explicit that every component of a
Heap
must use the sameOrd elem
implementation.
#1 is the simplest and I know it's generally recommended as a best practice in the Haskell space. Move the Ord
constraint to merge
and everything works:
data Heap : Type -> Type where
Empty : Heap elem
Node : Int -> elem -> Heap elem -> Heap elem -> Heap elem
-- `Ord` constraint moved from data constructors to function
-- |
-- V
merge : Ord elem => Heap elem -> Heap elem -> Heap elem
merge heap Empty = heap
merge Empty heap = heap
merge h1@(Node _ elem1 left1 right1) h2@(Node _ elem2 left2 right2) =
if elem1 <= elem2
then makeT elem1 left1 (merge right1 h2)
else makeT elem2 left2 (merge h1 right2)
where
rank : Heap elem -> Int
rank Empty = 0
rank (Node r _ _ _) = r
makeT : elem -> Heap elem -> Heap elem -> Heap elem
makeT x left right = if rank left >= rank right
then Node (rank right + 1) x left right
else Node (rank left + 1) x right left
The alternative might be necessary in certain cases, as it was in mine. In my case, my data type is an invariant for a binary tree data type, and it tracks the minimum/maximum value in the tree. So certain data constructors have an Ordered
constraint, and the RHS of the data constructors themselves use functions from that interface (minimum
and maximum
). As such, the constraint has to be available in the data constructor.
What I found out (by pure "I wonder if this works") is that interface constraints can both be named and they can be used in type signatures, meaning that a type constructor can accept a concrete interface implementation as a parameter. Here's the same example reworked so that Heap
has an added (ord : Ord elem)
parameter, ensuring that every node in the heap uses the same Ord
implementation:
-- Concrete `Ord` implementation as a parameter to the data type, ensuring that every component of
-- a `Heap` uses the _same_ ordering implementation.
-- |
-- V
data Heap : (elem : Type) -> (ord : Ord elem) -> Type where
Empty : {ord : Ord elem} -> Heap elem ord
Node : {ord : Ord elem} -> Int -> elem -> Heap elem ord -> Heap elem ord -> Heap elem ord
-- `Ord` constraint is given a name so that it can used in the `Heap` type constructor.
-- |
-- V
merge : (ord : Ord elem) => Heap elem ord -> Heap elem ord -> Heap elem ord
merge heap Empty = heap
merge Empty heap = heap
merge h1@(Node _ elem1 left1 right1) h2@(Node _ elem2 left2 right2) =
if elem1 <= elem2
then makeT elem1 left1 (merge right1 h2)
else makeT elem2 left2 (merge h1 right2)
where
rank : Heap elem ord -> Int
rank Empty = 0
rank (Node r _ _ _) = r
makeT : elem -> Heap elem ord -> Heap elem ord -> Heap elem ord
makeT x left right = if rank left >= rank right
then Node (rank right + 1) x left right
else Node (rank left + 1) x right left
-- Define helpers for the data constructors which use type constraints, so that the compiler can
-- automatically search for an implementation when creating instances of `Heap`
empty : (ord : Ord elem) => Heap elem ord
empty = Empty
node : (ord : Ord elem) => Int -> elem -> Heap elem ord -> Heap elem ord -> Heap elem ord
node = Node
example : (ord : Ord String) => Heap String ord
example = node 10 "foo" empty (node 5 "bar" empty empty)
Since I stumbled upon this on my own, I don't know whether it's recommended per se (some input on that front would be appreciated), but it seems to work. Generally I would stick with option #1 unless it's not possible to do so.
from idris2.
The error message now mentions the binding places of these two candidates.
Unfortunately the locations are too loose and appear to be the same entire LHS:
Possible correct results:
conArg (implicitly bound at Issue34.idr:18:26--20:67)
conArg (implicitly bound at Issue34.idr:18:26--20:67)
from idris2.
Related Issues (20)
- Type checker does not terminate when comparing codata types. HOT 2
- Remove `=` sugar for propositional Equality HOT 3
- Failure to eliminate pattern case when matching by type HOT 3
- `unsafePerformIO` can be optimized out HOT 4
- Overly eager auto implicit in GADT ctor field's type results in typechecking failure
- Source file "Main.idr" is not in the source directory when invoking compiler with `--source-dir` HOT 2
- [ regression ] `Uninhabited (LTE 1 0)` will no longer be found HOT 2
- `idris2 --init` doesn't check a name of a package
- Totality checker fails to recognize missing cases on irrelevant parameter in irrelevant function HOT 1
- Regression in #3234, backticked infix operators are printed incorrectly HOT 1
- Postfix functions are parsed as if inside unquote when are right after unquote HOT 1
- Remove 'Closed' state from linear network API
- Type checking issue with Idris2 Load instruction in dependent context HOT 1
- Fedora FC38, FC39 with racket 7.9 — "make bootstrap-racket" freezes on compilation HOT 2
- No Nested ":" allowed? HOT 5
- FFI: segfault for conflicting names in C++
- Doc: "Multiplicities" section roadmap HOT 4
- [ bug ] Buggy `Data.Fin.fromInteger` in the presence of negative integer literals HOT 1
- Type information is lost/changed when inlining a function (and it's not clear why) HOT 5
- Inconsistency in totality checker with different constants values and representations
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from idris2.