I am trying to implement binary tree as a typeclass:
class BinaryTree bt where
empty :: bt a -> Bool
empty = isNothing . root
emptyTree :: bt a
branch :: a -> bt a -> bt a -> bt a
root :: bt a -> Maybe a
lbranch :: bt a -> bt a
rbranch :: bt a -> bt a
And I want to illustrate that binary trees are data containers using this definition:
instance BinaryTree bt => Functor bt where
fmap f bt = case root bt of
Nothing -> emptyTree
Just a -> branch (f a) (f <$> lbranch bt) (f <$> rbranch bt)
I've got:
BinaryTree/BinaryTree.hs:18:10: error:
• The constraint ‘BinaryTree bt’
is no smaller than the instance head ‘Functor bt’
(Use UndecidableInstances to permit this)
• In the instance declaration for ‘Functor bt’
Using UndecidableInstances
absolutely makes the code compile. But I am wondering that is this a proper case to use UndecidableInstances
?
I've read about articles like "When is UndecidableInstances safe?", but I do not really get it.
Update 1: About "Why using typeclasses"
It is a part of an exploration, in which I try to distinct complete binary trees and perfect binary trees from general binary trees by Haskell code, in a proper way, by describing the property of them in Haskell code. (The properties are: 1) complete binary trees are one-to-one correspond to lists, bt2list
and list2bt
are available, and 2) perfect binary trees is the combine of two same-depth perfect binary trees. )
Specifically, the ultimate goal is to declare a type for complete binary trees, that refuses a value which is a binary tree but not a complete binary tree when compiling. (And also for perfect binary trees.)
The exploration is still not given up and suggestions are welcomed. Many thanks!