【问题标题】:Getting specific values from a function returned from a monad I.E. the first Int from: "Int -> (a, Int, [Int])"从 monad I.E. 返回的函数中获取特定值第一个 Int 来自:“Int -> (a, Int, [Int])”
【发布时间】:2021-12-13 07:39:47
【问题描述】:

感谢热心的互联网人抽出宝贵时间。

我正在尝试实现一个类型为 Int -> (a, Int, [Int]) 的 Monad,我需要能够从 Monad 中提取每个值。

目前我正在尝试实现、fmap、return、get 和 put。问题是我不知道如何从 Int -> (a, Int, [Int]) 类型中检索值。

monad 的类型定义为newtype M a = M { run :: Int -> (a, Int, [Int]) } 其中第一个 int 是开始计算的值(如 Collat​​z 序列),a 是结果,Int 在tuple 是最终状态(如果执行 Collat​​z 序列,它将以 1 结束),Ints 列表是导致最终状态的所有计算的日志(IE 是: [5, 16, 8, 4, 2, 1] 如果开始的 int 是 5)

到目前为止,我已经找到了检索元组中值的方法

newtype M a = M { run :: Int -> (a, Int, [Int]) }

getVals :: M a -> Int -> a
getVals m z = a where
    (a, _, _) = run m z

getState :: M a -> Int -> Int
getState m z = mid where
  (_, mid, _) = run m z

getLog :: M a -> Int -> [Int]
getLog m z = ws where
    (_, _, ws) = run m z

(z 应该是计算的初始整数值:例如 collat​​z 序列)

但我无法从 Int -> (a, Int, [Int]) 中检索到初始的 Int

只是为了澄清我在询问如何从 Int -> (a, Int, [Int]) 类型中检索个人详细信息。 Monad 的东西只是上下文。

【问题讨论】:

  • 我并不完全清楚你想要你的类型的语义是什么。如果您编辑您的问题以使其更清晰(最好还添加一些示例),那么我可以更新我的答案以包括如何实现更多类型类和方法。
  • 舌尖在脸颊上:getInitialInput :: M a -> Int -> Int; getInitialInput m z = z。但只是轻微的;如果这不能满足您的需求,那么可能值得考虑一下具体原因。
  • 您似乎想从函数A -> B 中提取A 类型的值。为什么你认为这是可能的?如果我去市场看到“1 公斤苹果 1 欧元”的标语,我无法从该交易中获得 1 欧元。
  • 你确定你想要一个单子吗?如果您只想要 Collat​​z 序列,那么您可以为它编写一个递归函数,而无需使用 monad。或者,如果您愿意,可以使用unfold

标签: haskell functional-programming


【解决方案1】:

只有一种方法(直到等价)可以将任何类型变成Functor。这是适合您的类型:

instance Functor M where
    fmap f m = M $ \z -> let (a, mid, ws) = run m z in (f a, mid, ws)

至于如何“检索”Int 左侧的->,这不是存储在类型中的内容。相反,当函数最终被调用时,您可以访问它。例如,在我上面的例子中,您可以将其作为 z 变量访问。

【讨论】:

    【解决方案2】:

    首先,风格要点:您应该将元组重新定义为具有命名字段的数据类型:

    data MD a = MD {
       mValue :: a,
       mState :: Int,
       mLog :: [Int]}
    

    现在是肉。

    像这样的一元动作的一般形式是

    myAction :: M a
    myAction = M $ \oldState ->
        ... stuff ...
        MD result newState newLogs
    

    lambda 参数oldState 是您要查找的Int

    您的getState 如下所示:

    getState :: M Int
    getState = M $ \s -> MD s s []
    

    因此,您将状态参数作为结果返回,并将其原封不动地传递给下一个操作。这样做不会导致写入任何日志。

    你不能写 getLog 来检查这个 monad 中的当前日志,因为日志列表没有作为状态的一部分传递。但是,您可以编写一个接受M 操作、运行它并为您提供结果日志以及将其写入外部日志的日志。

    getLog :: M a -> M ([Int], a)
    getLog action = M $ \oldState ->
       let MD result newState innerLog = run action oldState
       in MD (innerLog, result) newState innerLog
    

    你也会想要一个动作

    writeLog :: Int -> M ()
    

    您的绑定>>= 将具有以下类型:

    (>>=) :: M a -> (a -> M b) -> M b
    

    所以你的Monad 实例将要启动

    instance Monad M where
        v >>= f = M $ \oldState ->
    

    新日志将是来自v 的日志与来自f 输出的日志连接。其余的留给读者练习。

    【讨论】:

    • 非常感谢! \oldstate 解释比我的教授教过的任何东西/我在任何地方在线阅读的任何东西都更好地帮助了我。我现在正在执行您解释的内容,但我只是想尽快表示感谢。
    • 谢谢,但正确的做法是点赞,如果合适,请点击大勾号接受答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多