我知道在IO运算符的Scalaz中有一些几乎相同的实现,如putStrLn :: String -> IO (
)和getLine :: IO String
,但我的意思是Scala标准API为什么没有这样的等价物?
我知道Scala不是Haskell的纯语言,并且有副作用,但我认为这种数据类型是如此描述性和有用。
我不知道Try
,Option
或Either
是否能胜任这项工作。
答案 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的流线型,更强大和更健全的类型系统可能会成为更好的基础。