@ Андре только что попытался обеспечить минимальное исправление для вашего кода.Идиоматический способ реализовать вашу задачу обработки ошибок в Haskell - это использовать монаду Error
.Основной причиной этого является возможность повторного использования библиотечной функции liftM2
для реализации combine
.throwError
и return
можно заменить на Left
и Right
, но общие функции более четко объясняют назначение вашего кода.
module Err where
import Control.Monad (liftM2)
import Control.Monad.Error (throwError)
data BST2 a = EmptyBST2 | Node2 a (BST2 a) (BST2 a) deriving Show
combine root = liftM2 (Node2 root)
insert2 :: (Ord a) => a -> BST2 a -> Either String (BST2 a)
insert2 elem EmptyBST2 = return $ Node2 elem EmptyBST2 EmptyBST2
insert2 elem (Node2 root left right)
| (elem == root) = throwError "insert2 error: Element already exists."
| (elem < root) = combine root (insert2 elem left) (return right)
| otherwise = combine root (return left) (insert2 elem right)
Обратите внимание, что combine
может быть короче: combine = liftM2 . Node2
или длиннее: combine root left right = liftM2 (Node2 root) left right
.Используйте стиль, который вы понимаете лучше всего.
Также некоторые комментарии относительно ошибок @Andre исправлены:
insert2
не был полиморфным в типе ошибки - он всегда возвращал String
вслучай неудачи.Поэтому он использовал String
в объявлении типа вместо b
. - В отличие от списков, упорядоченные коллекции не могут хранить какие-либо типы - только типы, которые можно сравнивать (упорядочивать), могут быть помещены в дерево.Поэтому он добавил ограничение
Ord a =>
на тип значения дерева, чтобы указать, что для типа должны быть реализованы <
и ==
. insert2
возвращает Either
.Вы пытались передать Left
или Right
в Node2
, и Node2 root (Left foo) right
не удалось, потому что ожидалось Node2 a
, но Either String (Node2 a)
предоставлено.
Наконец, еще одна причина использовать throwError
и return
заключается в том, что функция становится общей:
insert2 :: (Ord a, MonadError String m) => a -> BST2 a -> m (BST2 a)
, и вы можете использовать ее с экземплярами MonadError
, отличными от Either
, но вам нужно добавить прагму {-# LANGUAGE FlexibleContexts #-}
вначало вашего исходного файла до объявления module
.