Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 哈斯克尔的符号数学_Haskell - Fatal编程技术网

Haskell 哈斯克尔的符号数学

Haskell 哈斯克尔的符号数学,haskell,Haskell,这是我对数学的符号表示和一个求值函数。我对单子的了解有限,这可能是一个问题,如果我的求值函数中有一个除零的值,我想返回一个无值。由于许多不同的原因,当我尝试运行evalExpr(Const 3)或任何更复杂的程序时,它在运行时失败。我有什么遗漏吗?我想你想要的版本是: import Control.Monad (liftM2) infixl 4 :+:, :-: infixl 5 :*:, :/: data Expr a = Const a | (Expr a) :+

这是我对数学的符号表示和一个求值函数。我对单子的了解有限,这可能是一个问题,如果我的求值函数中有一个除零的值,我想返回一个无值。由于许多不同的原因,当我尝试运行
evalExpr(Const 3)
或任何更复杂的程序时,它在运行时失败。我有什么遗漏吗?

我想你想要的版本是:

import Control.Monad (liftM2)

infixl 4 :+:, :-: 
infixl 5 :*:, :/:

data Expr a  = Const a 
         | (Expr a) :+: (Expr a) 
         | (Expr a) :-: (Expr a)
         | (Expr a) :*: (Expr a)
         | (Expr a) :/: (Expr a)
         deriving (Show, Eq)

evalExpr (Const a) = a 
evalExpr (a :+: b) = liftM2 (+) (evalExpr a) (evalExpr b)
evalExpr (a :-: b) = liftM2 (-) (evalExpr a) (evalExpr b)
evalExpr (a :*: b) = liftM2 (*) (evalExpr a) (evalExpr b)
evalExpr (a :/: b) = if (evalExpr b) == 0 
        then Nothing 
         else liftM2 (/) (evalExpr a) (evalExpr b)
Const
的情况下(
返回a
而不是
a
),当您检查0(
if(evalExpr b)==返回0而不是
if(evalExpr b)==0
)时,这些更改使用了正确的一元(在本例中是
可能

(并不是说两者都可以使用
只是
而不是
返回
,因为它肯定是我们正在使用的Maybe monad。)

通过修复
evalExpr
的类型,我能够更容易地找出问题所在。liftM2的使用使得Haskell表达式非常通用,因此它有许多不同的版本,要么编译后不能按预期工作,要么编译失败,消息混乱。一旦类型被修复,编译器马上告诉我是
常量和
=
表达式导致了问题

您可能还对使用应用程序函数
而不是
liftM2
感兴趣,因为无论有多少参数,都可以使用这些函数:

import Control.Monad (liftM2)

infixl 4 :+:, :-: 
infixl 5 :*:, :/:

data Expr a  = Const a 
         | (Expr a) :+: (Expr a) 
         | (Expr a) :-: (Expr a)
         | (Expr a) :*: (Expr a)
         | (Expr a) :/: (Expr a)
         deriving (Show, Eq)

evalExpr :: (Eq a, Num a, Fractional a) => (Expr a) -> Maybe a
evalExpr (Const a) = return a 
evalExpr (a :+: b) = liftM2 (+) (evalExpr a) (evalExpr b)
evalExpr (a :-: b) = liftM2 (-) (evalExpr a) (evalExpr b)
evalExpr (a :*: b) = liftM2 (*) (evalExpr a) (evalExpr b)
evalExpr (a :/: b) = if (evalExpr b) == return 0
        then Nothing 
        else liftM2 (/) (evalExpr a) (evalExpr b)
有关详细信息,请查阅应用程序函子。有一个很好的描述

更新

@gallais就分部案件的风格提出了一点看法。为了清晰起见,我不打算提及它,但我可能会这样做:

triad <$> arg1 <*> arg2 <*> arg3

在这种情况下,还有其他一元辅助函数很有用,例如
guard
when
,除非
,请参见。

您认为
evalExpr
应该有什么类型?它实际上有什么类型(通过
:type
)询问GHCi)?这是否向您解释了一些问题?
evalExpr
Const
案例应该是
返回a
。是的,我尝试使用:t,得到了我期望的类型(Num(可能是a))=>Expr a->maybea换言之,它接受带有maybea数字的表达式并返回maybeanumber@KyleMcKean我想你可能想要
numa=>Expr a->可能是a
,否则你最终会得到与
Expr a->可能(可能是a)
相当的东西,由于
可能a
Num
的一个实例@KyleMcKean
evalExpr b
将返回a
可能a
,而不是
a
,因此如果evalExpr b==0,您可以执行
,否则,您试图将一个数字与非数字进行比较。您可能需要在最后一个子句中排除
evalExpr b
。一元风格是合适的。
triad <$> arg1 <*> arg2 <*> arg3
evalExpr :: (Eq a, Num a, Fractional a) => (Expr a) -> Maybe a
evalExpr (Const a) = return a 
evalExpr (a :+: b) = (+) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :-: b) = (-) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :*: b) = (*) <$> (evalExpr a) <*> (evalExpr b)
evalExpr (a :/: b) = (/) <$> (evalExpr a) <*> (failOn 0 $ evalExpr b)

failOn x a = case a of
    Just x -> Nothing
    _      -> a
...
evalExpr (a :/: b) = (/) <$> (evalExpr a) <*> (failOn (==0) $ evalExpr b)

failOn f a = do
    b <- fmap f a
    if b then mzero else a