什么是Scala标准API中的IO Haskell Monad等价物?

时间:2017-06-23 13:08:49

标签: scala haskell functional-programming io-monad

我知道在IO运算符的Scalaz中有一些几乎相同的实现,如putStrLn :: String -> IO ()和getLine :: IO String,但我的意思是Scala标准API为什么没有这样的等价物? 我知道Scala不是Haskell的纯语言,并且有副作用,但我认为这种数据类型是如此描述性和有用。 我不知道TryOptionEither是否能胜任这项工作。

2 个答案:

答案 0 :(得分:8)

Scala的标准库没有IO monad。像Monix,Scalaz,FS2和现在的Cats这样的库提供IO monads(或具有并发支持的Task)。如果你想要haskell类型编程,你将需要其中一个库,特别是Cats或Scalaz,还有其他有用的工具和类型类(例如实际的functor和monad类型)。

答案 1 :(得分:1)

Scala具有隐含的环境副作用,就像C♯,Java,C ++,Objective-C,Swift,C,Pascal,Basic,Perl,PHP,Python,Ruby,ECMAScript等。{没有类型{1}}。

有第三方库提供// // CalculatorBrain_IOS10.swift // Calculator_IOS10 // // Created by Theophilos Aravanis on 4/14/17. // Copyright © 2017 Theophilos Aravanis. All rights reserved. // import Foundation func factorial(_ op1: Double) -> Double { if (op1 <= 1.0) { return 1.0 } return op1 * factorial(op1 - 1.0) } struct CalculatorBrain { var result:Double? { get { return accumulator?.0 } } // @available(*, deprecated, message: "Use evaluate instead") var resultIsPending = false private var accumulator:(digit:Double, description:String?, errorMessage:String?)? private enum MemoryVarible { case operand(Double) case operation(String) case variable(String) } private var memorySequence = [MemoryVarible]() private enum Operation { case constant(Double) case nullOperation(() -> Double, String) case unaryOperation((Double) -> Double, (String) -> String, (Double) -> String?) case binaryOperation((Double,Double) -> Double, (String, String) -> String, (Double,Double) -> String?) case equals } private var operations:Dictionary<String,Operation> = [ "rand": .nullOperation({Double(arc4random()) / Double(UInt32.max)}, "rand()"), "π" : .constant(M_PI), "e" : .constant(M_E), "√" : .unaryOperation(sqrt,{"√(" + $0 + ")"},{$0 < 0 ? "Sqrt of negative number" : nil}), "cos" :.unaryOperation(cos,{"cos(" + $0 + ")"},{ _ in nil}), "∓" : .unaryOperation({-$0},{"-(" + $0 + ")"},{ _ in nil}), "x²" :.unaryOperation({ pow($0, 2) }, { "(" + $0 + ")²" },{ _ in nil}), "x³" :.unaryOperation({ pow($0, 3) }, { "(" + $0 + ")³" },{ _ in nil}), "x⁻¹" :.unaryOperation({ 1 / $0 }, { "(" + $0 + ")⁻¹" },{ _ in nil}), "sin" :.unaryOperation(sin, { "sin(" + $0 + ")" },{ _ in nil}), "tan" :.unaryOperation(tan, { "tan(" + $0 + ")" },{ _ in nil}), "sinh" :.unaryOperation(sinh, { "sinh(" + $0 + ")" },{ _ in nil}), "cosh" :.unaryOperation(cosh, { "cosh(" + $0 + ")" },{ _ in nil}), "tanh" :.unaryOperation(tanh, { "tanh(" + $0 + ")" },{ _ in nil}), "ln" : .unaryOperation(log, { "ln(" + $0 + ")" },{ _ in nil}), "log" : .unaryOperation(log10, { "log(" + $0 + ")" },{ _ in nil}), "eˣ" :.unaryOperation(exp, { "e^(" + $0 + ")" },{ _ in nil}), "10ˣ" :.unaryOperation({ pow(10, $0) }, { "10^(" + $0 + ")" },{ _ in nil}), "x!" :.unaryOperation(factorial, { "(" + $0 + ")!" },{ _ in nil}), "xʸ" :.binaryOperation(pow, { $0 + "^" + $1 },{ _,_ in nil}), "+" : .binaryOperation(+,{$0 + "+" + $1},{ _,_ in nil}), "−" : .binaryOperation(-,{$0 + "-" + $1},{ _,_ in nil}), "÷" : .binaryOperation(/,{$0 + "÷" + $1}, {_,_ in nil }), "×" : .binaryOperation(*,{$0 + "*" + $1},{ _,_ in nil}), "=" : .equals ] mutating func clearAccumulator() { accumulator?.errorMessage = nil accumulator?.description = " " accumulator?.digit = 0 } mutating func evaluate(using variables: Dictionary<String,Double>? = nil) -> (result: Double?, isPending: Bool, description: String) { let (result, isPending, description, _) = evaluateWithErrorReport(using: variables) return (result, isPending, description) } mutating func performOperation(_ symbol: String) { memorySequence.append(MemoryVarible.operation(symbol)) } mutating func setOperand(_ operand: Double) { memorySequence.append(MemoryVarible.operand(operand)) } mutating func setOperand(variable named: String) { memorySequence.append(MemoryVarible.variable(named)) } mutating func evaluateWithErrorReport(using variables: Dictionary<String,Double>? = nil) -> (result: Double?, isPending: Bool, description: String, errorDescription: String?) { var pendingBinaryOperation:PendingBinaryOperation? var calculationDescription:String? { get { if pendingBinaryOperation == nil { return accumulator?.description } else { return pendingBinaryOperation!.calculationDescription(pendingBinaryOperation!.descriptionOperand, accumulator?.description ?? " ") } } } var line:String? { get { return calculationDescription } } func performOperation(_ symbol:String){ if let currentOperation = operations[symbol] { switch currentOperation { case .nullOperation(let function, let nullDiscription): accumulator = (function(), nullDiscription, nil) case .constant(let value): accumulator = (value,symbol, nil) case .unaryOperation(let function, let unaryDescription, let unaryMemory): if accumulator != nil { accumulator = (function(accumulator!.digit), unaryDescription(accumulator!.description!), unaryMemory(accumulator!.digit)) } case .binaryOperation(let binaryFunction, let binaryDescription, let binaryError): if accumulator != nil { doAPendingBinaryOperation() resultIsPending = true pendingBinaryOperation = PendingBinaryOperation( calculationError:binaryError, mathFunction: binaryFunction, calculationDescription:binaryDescription, firstOperand: accumulator!.digit, descriptionOperand:(accumulator?.description)! ) accumulator = nil } case .equals: doAPendingBinaryOperation() resultIsPending = false } } } func doAPendingBinaryOperation() { if pendingBinaryOperation != nil && accumulator != nil { accumulator!.description = calculationDescription! accumulator!.digit = pendingBinaryOperation!.perform(with: accumulator!.digit) accumulator!.errorMessage = "Future enhancement" pendingBinaryOperation = nil } } struct PendingBinaryOperation { let calculationError: (Double, Double) -> String? let mathFunction: (Double, Double) -> Double let calculationDescription: (String, String) -> String let firstOperand: (Double) let descriptionOperand:(String) func perform(with secondOperand:(Double)) -> Double { return (mathFunction(firstOperand, secondOperand)) } func performDecription(with secondOperan:(String)) -> String { return (calculationDescription(descriptionOperand, secondOperan)) } } func setOperand(_ operand:Double) { accumulator = (operand, String(Int(operand)), nil) } func setOperand(variable named: String) { accumulator = (variables?[named] ?? 0, named, nil) } for item in memorySequence { switch item { case .operand(let operand): setOperand(operand) case .operation(let operation): performOperation(operation) case .variable(let variable): setOperand(variable:variable) } } if pendingBinaryOperation != nil { return (accumulator!.digit, true, pendingBinaryOperation!.calculationDescription(pendingBinaryOperation!.descriptionOperand, accumulator!.description ?? ""), accumulator?.errorMessage) } else { return (accumulator!.digit, false, accumulator!.description ?? "", accumulator?.errorMessage) } } // end of evaluate with errors } 类型,但它没有提供与Haskell相同的保证:在Scala中,Haskell只有很少的转义符号(Imports System.Threading Public Class Form1 # Path to your ClickOnce app Dim startPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Programs) _ & '"\"' & '"remaining path to your app"' & '".appref-ms"' # Path to your shell which is also a clickonce app(this one) Dim spath As String = Application.StartupPath & '"\"' & My.Application.Info.AssemblyName _ & '".exe"' # This sets the registry to start your shell which in turn starts your app. # I did this so that if the app is closed, they see the shell background. # You can add controls to your shell to restart the app, shutdown.... #Just be cautious, make sure your app is 100% done and updates on it's own before you # disable the ability to get back to windows explorer. # Other wise you could have a very bad day. My.Computer.Registry.SetValue('"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\ _ CurrentVersion\Winlogon"', '"Shell"', spath) Thread.Sleep(500) Process.Start(startPath) End Class ),几乎所有都是逃生舱。

然而,有一些想法,我相信甚至研究Scala中效果系统的原型,Dotty的流线型,更强大和更健全的类型系统可能会成为更好的基础。