【问题标题】:Haskell Monads EitherHaskell Monads 要么
【发布时间】:2014-07-03 20:03:55
【问题描述】:

我对 Haskell 中的数据类型有一点问题,我想我应该先发布一些代码来帮助理解问题

helper ::  (MonadMask a, MonadIO a, Functor a) => Expr -> String ->  a (Either InterpreterError Int)
helper x y = ( getEval ( mkCodeString x y ) )

-- Creates Code String
mkCodeString :: (Show a) => a -> String -> String
mkCodeString x y = unpack (replace (pack "Const ") (pack "") (replace (pack "\"") (pack "") (replace  (pack "Add") (pack y) (pack (show x) ) ) ) ) 

-- Calculates String
getEval :: (MonadMask m, MonadIO m, Functor m) => [Char] -> m (Either InterpreterError Int)
getEval str = (runInterpreter (setImports ["Prelude"] >> interpret str (as ::Int)))

-- | A test expression.
testexpression1 :: Expr
testexpression1 = 3 + (4 + 5)

-- | A test expression.
testexpression2 :: Expr
testexpression2 = (3 + 4) + 5

-- | A test expression.
testexpression3 :: Expr
testexpression3 = 2 + 5 + 5

我使用像“helper testexpression3”(+)这样的辅助函数,它返回值“Right 12”,类型为“Either InterpreterError Int”,但我只想拥有“Int”值“12” "

我尝试了函数 -> "getValue (Right x) = x" 但我没有得到那个 Int 值。 经过一段时间的测试,我认为这是我使用的 Monad 的问题。

如果我像这样测试辅助函数的类型: ":t (helper testexpression1 "(+)")" 我会得到: "(... :: (Functor a, MonadIO a, MonadMask a ) => a (InterpreterError Int)"

我怎样才能使这样的工作: 写"getValue(helper testexpression1 "(+)")" 得到"12" :: Int

我知道代码没有意义,但它是一个家庭作业,我想用 haskell 尝试一些东西。希望你比我有更多的想法。

对不起,我的英语不好,我已经开始学习英语,但我才刚刚开始,谢谢你的每一个想法和一切。

编辑,以下是代码中缺少的内容:

import Test.HUnit (runTestTT,Test(TestLabel,TestList),(~?))
import Data.Function (on)
import Language.Haskell.Interpreter -- Hint package 
import Data.Text
import Data.Text.Encoding
import Data.ByteString (ByteString)
import Control.Monad.Catch

-- | A very simple data type for expressions.
data Expr = Const Int | Add Expr Expr deriving Show

-- | 'Expression' is an instance of 'Num'. You will get warnings because
--   many required methods are not implemented.
instance Num Expr where
    fromInteger = Const . fromInteger
    (+) = Add

-- | Equality of 'Expr's modulo associativity.
instance Eq Expr where
    (==) x1 x2 = True --(helper x1 "(+)") ==  (helper x2 "(+)") && (helper x1 "(*)") == (helper x2 "(*)")  

这些函数也在文件中......我文件中的所有其他内容都是我为我创建的一些测试用例。

【问题讨论】:

  • 您的代码很难理解,主要是因为您使用了未显示的函数和数据类型(MonadMaskExprrunInterpreter)。请发布最少量的代码来编译和演示您遇到的问题。
  • 你试图对helper的结果进行模式匹配,就好像它是Either a b,但它是(MonadMask m, MonadIO m, Functor m) => m (Either a b),所以你必须先解开monad层才能对@进行模式匹配987654329@ 或 Right 构造函数。
  • 您可以在main:main = do { result <- helper testexpression1 "(+)"; case result of { Right x -> print x; Left err -> putStrLn "There was an error!" } } 中执行类似的操作,但可以随意将其重新格式化为多行。简短的回答是,您在某些时候被限制在 IO 内部,并且您无法在 Haskell 中逃离 IOunsafePerformIO 除外,您可能会猜到它的名称并不安全日常使用,它会导致非常奇怪的问题,并且主要存在于高级代码中的低级操作,除非您知道自己在做什么,否则不要使用它!)。
  • 哦,这很快 :D 谢谢。现在我已经更新了上面的代码,但是你已经回答了我的问题。好的,让我们看看 unwarp monad 是什么意思:D 谢谢
  • @user3803077 一些 monad 只是一种数据结构,例如 MaybeEither。事实上,大多数(如果不是全部)不是建立在 IO 之上的 monad 只是一个数据结构。执行“单子”动作只是为该单子构建数据结构。 IO 是一个特殊的 monad,你无法访问它的构造函数,而且它确实是不纯的,每次运行它时你都可以得到不同的值(例如从文件中读取)。任何只是一个数据结构的 monad 通常都可以“展开”以获得最终结果,这意味着它只是被解构以获取一些值。

标签: haskell types eval monads either


【解决方案1】:

helper textExpr "(+)" 不是Either InterpreterError Int 类型,而是(MonadMask a, MonadIO a, Functor a) => a (Either InterpreterError Int) 类型。出于我们的目的,这个后来的 tyoe 可以被视为IO (Either InterpreterError Int)

一般来说,IO a 类型的东西(例如IO (Either InterpreterError Int))不包含,在最严格的意义上,a 类型的值,所以你不能随便提取一个值。 IO a 类型的东西是一个动作,当它被执行时,将产生一个a 类型的值。 Haskell 只执行一项操作,称为 main。也就是说,它使我们能够轻松地从较小的操作中构建更大的操作。

main = helper textExpr "(+)" >>= print

那里的那个操作符(>>=)是一个单子绑定。有关一般 monad 的更多信息,请参阅You Could Have Invented Monads!。有关如何构建 IO Monad 的想法,请参阅Free Monads for Less (Part 3 of 3): Yielding IO(在“谁需要真实世界?”下)或Idris' implementation of IO——但请记住,IO Monad 在 Haskell 中是不透明和抽象的;不要指望能够从IO a 值中获得a 值,除非您正在编写main(应用程序)。

【讨论】:

    猜你喜欢
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 2014-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多