Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.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_Monads_Maybe - Fatal编程技术网

Haskell 也许是单子结构

Haskell 也许是单子结构,haskell,monads,maybe,Haskell,Monads,Maybe,我目前正在与Haskell的一个新元素作斗争:单子。因此,我通过创建一个(>=)运算符的示例了解到这一点,该运算符仅在可能类型上执行函数(将其实际整数值作为参数),前提是该类型不等于Nothing,否则返回Nothing: (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b Nothing >>= _ = Nothing (Just x) >>= f = f x eval x >>= (.

我目前正在与Haskell的一个新元素作斗争:单子。因此,我通过创建一个
(>=)
运算符的示例了解到这一点,该运算符仅在
可能
类型上执行函数(将其实际整数值作为参数),前提是该类型不等于
Nothing
,否则返回
Nothing

(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= _ = Nothing
(Just x) >>= f = f x
eval x >>= (...) = Nothing >>= (...) = Nothing
eval x >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> eval y >>= (...)) 
= Just n >>= (\n -> Nothing)
= Nothing
但是,我不太清楚它在以下情况下是如何工作的:

eval (Val n) = Just n
eval (Div x y) = eval x >>= (\n ->
    eval y >>= (\m ->
        safediv n m))

在我看来,
(>>=)
操作符只需要取一个
可能
值和一个返回值的函数,但是在本例中,使用代码似乎是取一个
可能
值的2倍,一个函数取一次。但是,我被告知,它计算
x
,将结果放入
n
,然后计算
y
,将结果放入
y
,然后对这两个对象执行
safediv
函数。虽然我不知道
(>>=)
操作符是如何在这里发挥作用的;这是怎么回事

你可以这样读:

eval (Div x y) = eval x >>= (\n ->
    eval y >>= (\m ->
        safediv n m))
当你想做
eval(Div x y)

  • 第一次
    评估x
    • if was
      只是n
      (使用第一个>=
    • 然后使用
      n
      查看
      eval y
      (使用第一个>=
      • 如果最后一个是
        ,只有m
        (第二个>=
      • 然后取
        m
        ,做一次(第二次>=
      • savediv n m
        返回结果-您仍然拥有闭包中的
        n
在任何其他CAE中,返回
Nothing

所以这里的
(>>=)
只是帮助您解构

也许在
do
表格中更容易阅读和理解:

eval (Val n) = Just n
eval (Div x y) = do
    n <- eval x
    m <- eval y
    safediv n m
2. <代码>评估x=无和
评估y=仅n
: 这是一样的:

eval x >>= (...) = Nothing >>= (...) = Nothing
3. <代码>评估x=仅n和
评估y=无
eval x >>= (...) = Nothing >>= (...) = Nothing
eval x >>= (\n -> eval y >>= (...))
= Just n >>= (\n -> eval y >>= (...)) 
= Just n >>= (\n -> Nothing)
= Nothing
4. <代码>评估x=仅n和
评估y=仅m
eval x >>= (\n -> Just m >>= (...))
= Just n >>= (\n -> Just m >>= (...)) 
= Just n >>= (\n -> Just m >>= (\m -> safediv n m))
= (first >>= for Just) = Just m >>= (\n -> safediv n m)
= (second >>= for Just) = safediv n m

让我们进行元素追踪来说明它是如何工作的。如果我们有

eval (Div (Val 5) (Div (Val 0) (Val 1)))
然后我们可以把它分解成

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = eval (Val 5) >>=
        (\n ->
            eval (Div (Val 0) (Val 1)) >>=
                (\m ->
                    safediv n m
                )
        )

-- eval (Val 5) = Just 5

    = Just 5 >>=
        (\n ->
            eval (Div (Val 0) (Val 1)) >>=
                (\m ->
                    safediv n m
                )
        )

-- Just x >>= f = f x

    = (\n ->
        eval (Div (Val 0) (Val 1)) >>=
            (\m ->
                safediv n m
            )
      ) 5

-- Substitute n = 5, since the 5 is the argument to the `\n ->` lamba

    = eval (Div (Val 0) (Val 1)) >>=
        (\m ->
            safediv 5 m
        )
现在我们需要绕道计算
eval(Div(val0)(val1))

eval (Div (Val 0) (Val 1))
    = eval (Val 0) >>=
        (\n ->
            eval (Val 1) >>=
                (\m ->
                    safediv n m
                )
        )

-- eval (Val 0) = Just 0
-- eval (Val 1) = Just 1

eval (Div (Val 0) (Val 1))
    = Just 0 >>=
        (\n ->
            Just 1 >>=
                (\m ->
                    safediv n m
                )
        )

-- Just x >>= f = f x

eval (Div (Val 0) (Val 1))
    = (\n ->
        (\m ->
            safediv n m
        ) 1
      ) 0

    = (\n -> safediv n 1) 0
    = safediv 0 1
    = Just 0
现在回到我们最初对
eval
的调用,将
仅替换为0

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = Just 0 >>= (\m -> safediv 5 m)

-- Just x >>= f = f x

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = safediv 5 0

-- safediv x 0 = Nothing

eval (Div (Val 5) (Div (Val 0) (Val 1)))
    = Nothing
你有

eval (Val n) = Just n
由此我们得出结论,
eval
产生一个
可能
值。第二个等式,我们重写为

eval (Div x y) = 
  eval x >>= (\n ->
                    eval y >>= (\m ->
                                      safediv n m ) )
i、 e

看到了吗?每个
>>=
应用程序中只涉及一个函数。在顶部,它是
g
。但是
g
定义并使用–
h
,因此
h
的主体可以访问其参数
m
g
的参数
n

如果
eval x
生成了
Nothing
,那么
eval x>=g
就是
Nothing
,根据
>=
可能
类型的定义(
Nothing>==Nothing
),立即,并且不会尝试
eval y

但是如果它是
(Just…
,那么它的值只会被输入到绑定函数中(
Just x>=f=f x

因此,如果两个
eval
s都产生
Just…
值,则在可访问参数
n
m
的范围内调用
safediv n m
。它可能被定义为

safediv :: Num a => a -> a -> Maybe a
safediv n m | m == 0    =  Nothing
            | otherwise =  Just (div n m)    -- or something
所以
h::m->Maybe m
g::n->Maybe n
类型合适

-- assuming a missing type of "expressions", `Exp a`,
eval :: Num a => Exp a ->                                       Maybe a    
  -- Num a is assumed throughout, below
  eval (Div x y) =                                           -- Maybe a
  -- Maybe a >>= a ->                                           Maybe a
      eval x >>= g 
                 where
  --               a ->                                         Maybe a
  --                   Maybe a >>= a ->                         Maybe a 
                 g n =  eval y >>= h
                                   where
  --                                 a ->                       Maybe a
                                   h m =  safediv    n    m  -- Maybe a
  --                                      safediv :: a -> a ->  Maybe a
根据单子的绑定类型

(>>=) :: Maybe a -> 
              (a -> Maybe b) -> 
         Maybe            b
(>>=)::可能是a->
(a->也许b)->

也许b
我也是这么想的,但是我不知道(>>=)函数是如何工作的,它使用了两次,第一次(我读取它的方式)使用一个值和另一个值,然后再次使用该值和一个函数的结果。然而,运算符只接受一个值和一个函数?@user2999349它只是用来先从“just n”中获取“n”,然后第二次从“just m”中获取“m”@user2999349它是两个独立的应用程序,
>=
内部的应用程序有参数
eval y
(\m->safediv n m)
,而外部参数有as参数
eval x
(\n->eval y>>=(\m->safediv n m))