@Andreは自分のコードのための最小限の修正を提供しようとしました。 Haskellでのエラー処理タスクを実装するための慣用的な方法は、Error
モナドを使用することです。その主な理由は、combine
を実装するためにライブラリ関数liftM2
を再利用する可能性です。 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
を返しました。そこで、b
ではなく、型宣言でString
を使用しました。
- リストとは異なり、順序付けられたコレクションはどのタイプも格納できません。比較(順序付け)できるタイプのみをツリーに入れることができます。そこで、
<
と==
が型に実装されなければならないことを示すために、木の値の型に制約Ord a =>
を追加しました。
insert2
Either
を返します。 Node2 a
ではなくEither String (Node2 a)
が指定されているため、Left
またはRight
をNode2
およびNode2 root (Left foo) right
に渡そうとしましたが失敗しました。
最後に、throwError
とreturn
を使用するもう一つの理由は、機能が汎用的になることである:
insert2 :: (Ord a, MonadError String m) => a -> BST2 a -> m (BST2 a)
、あなたはEither
以外のMonadError
のインスタンスで使用することができますが、{-# LANGUAGE FlexibleContexts #-}
プラグマを追加する必要がありますソースファイルの先頭にあるmodule
宣言の前に。
実際には、insert2の2番目の引数が 'どちらの文字列(BST2 a) '、' BST2 a'でもかまいません。 – adamse
'combine'はちょうど' liftM2です。 Node2' – nponeccop