Haskell 多态函数使用左右
Haskell polymorphic function Using Either Left Right
我是 Haskell 的新手。我有以下类型:
type Variable = String
type Value = Float
type EvalError = [Variable]
type EvalResult = Either EvalError Value
我想创建一个函数,我将使用一个函数在 2 EvalResult
类型上使用它,并相应地得到一个 EvalResult
。
如果我得到 2 个值类型,我想对它们使用函数(例如 sum/sub),如果我得到 EvalError,我想 return EvalError.
我做了什么:
evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c
evalResultOp f (Left a) (Left b) = Left (a ++ b)
evalResultOp f (Left a) (Right b) = Left a
evalResultOp f (Right a) (Left b) = Left b
evalResultOp f (Right a) (Right b) = Right (f a b)
错误:
hs3.hs:46:34: error:
• Expecting one fewer arguments to ‘EvalResult’
Expected kind ‘* -> *’, but ‘EvalResult’ has kind ‘*’
• In the type signature:
evalResultOp :: (a -> b -> c)
-> EvalResult a -> EvalResult b -> EvalResult c
|
46 | evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c | ^^^^^^^^^^^^
hs3.hs:46:50: error:
• Expecting one fewer arguments to ‘EvalResult’
Expected kind ‘* -> *’, but ‘EvalResult’ has kind ‘*’
• In the type signature:
evalResultOp :: (a -> b -> c)
-> EvalResult a -> EvalResult b -> EvalResult c
|
46 | evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c | ^^^^^^^^^^^^
hs3.hs:46:66: error:
• Expecting one fewer arguments to ‘EvalResult’
Expected kind ‘* -> *’, but ‘EvalResult’ has kind ‘*’
• In the type signature:
evalResultOp :: (a -> b -> c)
-> EvalResult a -> EvalResult b -> EvalResult c
|
46 | evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c |
问题是您将 EvalResult
类型定义为:
type EvalResult = Either EvalError Value
因为 Either
是一个 type 构造函数,它有两种类型,这意味着你现在已经构造了一个类型(没有任何类型参数)。如果你写一个带有类型签名 (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c
的函数,那么 Haskell 最终将不得不构造类型 EvalResult a ~ Either EvalError Value a
,并且由于 Either
只接受两个类型参数,所以这是没有意义的.
我猜你想定义
type EvalResult <b>a</b> = Either EvalError <b>a</b>
或更短:
type EvalResult = Either EvalError
现在 EvakResult
因此就像一个类型构造函数,可以接受一个类型参数,然后该函数确实适用于类型。
我们可以这样写使实现更紧凑:
import Control.Monad(liftM2)
evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c
evalResultOp f (Left a) (Left b) = Left (a ++ b)
evalResultOp f x y = liftM2 f x y
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
是一个作用于 monadic 类型 m
的函数。 Either a
是一个 monadic 类型,它被定义为:
instance Monad (Either a) where
return = Right
(>>=) (Right x) f = f x
(>>=) (Left l) _ = Left l
liftM2
实现为:
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
liftM2 f xm ym = do
x <- mx
y <- my
return (f x y)
这是语法糖:
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
liftM2 f xm ym = mx >>= (\x -> my >>= \y -> return (f x y))
所以基本上我们通过检查 mx
是否是 Right
来评估 mx >>= (...)
,如果它是 Left
,我们 return Left
。因为我们已经处理了两个 Left
的情况,所以这种情况不再可能,所以我们知道第二个 EvalResult
是一个 Right
,在这种情况下我们因此 return 第一个Left
。如果 mx
是 Right x
,我们现在检查 my >>= (..)
并检查 my
的状态。如果my
是Left
,我们再return即Left
,否则,我们return即return (f x y)
,因为return
为一个 Either a
monad,实际上是 Right
,因此我们将 f x y
的内容包装在 Right
数据构造函数中。
我是 Haskell 的新手。我有以下类型:
type Variable = String
type Value = Float
type EvalError = [Variable]
type EvalResult = Either EvalError Value
我想创建一个函数,我将使用一个函数在 2 EvalResult
类型上使用它,并相应地得到一个 EvalResult
。
如果我得到 2 个值类型,我想对它们使用函数(例如 sum/sub),如果我得到 EvalError,我想 return EvalError.
我做了什么:
evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c
evalResultOp f (Left a) (Left b) = Left (a ++ b)
evalResultOp f (Left a) (Right b) = Left a
evalResultOp f (Right a) (Left b) = Left b
evalResultOp f (Right a) (Right b) = Right (f a b)
错误:
hs3.hs:46:34: error:
• Expecting one fewer arguments to ‘EvalResult’
Expected kind ‘* -> *’, but ‘EvalResult’ has kind ‘*’
• In the type signature:
evalResultOp :: (a -> b -> c)
-> EvalResult a -> EvalResult b -> EvalResult c
|
46 | evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c | ^^^^^^^^^^^^
hs3.hs:46:50: error:
• Expecting one fewer arguments to ‘EvalResult’
Expected kind ‘* -> *’, but ‘EvalResult’ has kind ‘*’
• In the type signature:
evalResultOp :: (a -> b -> c)
-> EvalResult a -> EvalResult b -> EvalResult c
|
46 | evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c | ^^^^^^^^^^^^
hs3.hs:46:66: error:
• Expecting one fewer arguments to ‘EvalResult’
Expected kind ‘* -> *’, but ‘EvalResult’ has kind ‘*’
• In the type signature:
evalResultOp :: (a -> b -> c)
-> EvalResult a -> EvalResult b -> EvalResult c
|
46 | evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c |
问题是您将 EvalResult
类型定义为:
type EvalResult = Either EvalError Value
因为 Either
是一个 type 构造函数,它有两种类型,这意味着你现在已经构造了一个类型(没有任何类型参数)。如果你写一个带有类型签名 (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c
的函数,那么 Haskell 最终将不得不构造类型 EvalResult a ~ Either EvalError Value a
,并且由于 Either
只接受两个类型参数,所以这是没有意义的.
我猜你想定义
type EvalResult <b>a</b> = Either EvalError <b>a</b>
或更短:
type EvalResult = Either EvalError
现在 EvakResult
因此就像一个类型构造函数,可以接受一个类型参数,然后该函数确实适用于类型。
我们可以这样写使实现更紧凑:
import Control.Monad(liftM2)
evalResultOp :: (a -> b -> c) -> EvalResult a -> EvalResult b -> EvalResult c
evalResultOp f (Left a) (Left b) = Left (a ++ b)
evalResultOp f x y = liftM2 f x y
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
是一个作用于 monadic 类型 m
的函数。 Either a
是一个 monadic 类型,它被定义为:
instance Monad (Either a) where return = Right (>>=) (Right x) f = f x (>>=) (Left l) _ = Left l
liftM2
实现为:
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c liftM2 f xm ym = do x <- mx y <- my return (f x y)
这是语法糖:
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
liftM2 f xm ym = mx >>= (\x -> my >>= \y -> return (f x y))
所以基本上我们通过检查 mx
是否是 Right
来评估 mx >>= (...)
,如果它是 Left
,我们 return Left
。因为我们已经处理了两个 Left
的情况,所以这种情况不再可能,所以我们知道第二个 EvalResult
是一个 Right
,在这种情况下我们因此 return 第一个Left
。如果 mx
是 Right x
,我们现在检查 my >>= (..)
并检查 my
的状态。如果my
是Left
,我们再return即Left
,否则,我们return即return (f x y)
,因为return
为一个 Either a
monad,实际上是 Right
,因此我们将 f x y
的内容包装在 Right
数据构造函数中。