Haskell 如何从数学角度查看高阶函数和IO操作?
我试图从第一原理来理解函数式编程,但我仍然停留在纯函数式世界和具有状态和副作用的不纯净现实世界之间的界面上。从数学角度看,Haskell 如何从数学角度查看高阶函数和IO操作?,haskell,functional-programming,io,higher-order-functions,purely-functional,Haskell,Functional Programming,Io,Higher Order Functions,Purely Functional,我试图从第一原理来理解函数式编程,但我仍然停留在纯函数式世界和具有状态和副作用的不纯净现实世界之间的界面上。从数学角度看, 什么是返回函数的函数 返回IO操作(如Haskell的IO类型)的函数是什么 详细说明:在我的理解中,纯函数是从一个域到另一个域的映射。最终,它是从计算机内存中的一些值到内存中其他一些值的映射。在函数式语言中,函数是以声明方式定义的;i、 例如,它们描述映射,但不描述需要对特定输入值执行的实际计算;后者由编译器派生。在一个有空闲内存的简化设置中,运行时将不会进行计算;相
- 什么是返回函数的函数
- 返回IO操作(如Haskell的IO类型)的函数是什么
(||) x = case x of True -> let f y = case y of True -> True
False -> True
in f
False -> let g y = case y of True -> True
False -> False
in g
- 对于以另一个函数为参数的函数,将值映射到值的结果一阶函数是什么?有数学描述吗(我肯定有,但我既不是数学家也不是计算机科学家)
- 一个返回函数的函数怎么样?我如何在心里“展平”这个构造,再次得到一个一阶函数,将值映射到值
在Haskell中,这种与现实世界的命令式交互被抽象为IO操作,编译器根据它们的数据依赖性对其进行排序。然而,我们并不直接将程序作为命令IO操作序列来编写。相反,有些函数返回IO操作(类型为
::IO a
)的函数)。但据我理解,这些不可能是真正的功能。它们是什么?如何根据上面概述的心智模型更好地思考它们?从数学上讲,接受或返回其他函数的函数根本没有问题。从集合S到集合T的函数的标准集合论定义如下:
f∈ s→ T意味着f⊂ s✕ T和两个条件成立:
- 如果
,则x::a
纯x::IO a
- 如果
,则f::a->b
fmap f::IO a->IO b
- 如果
和x::ioa
,则f::a->iob
x>=f::iob
putStrLn::String->IO()
forkIO::IO a->IO线程ID
- …还有上千个基本案例
- 我们在几个等式上求商:
fmap id=id
fmap f。fmap g=fmap(f.g)
=pure x>>=f
fx
=x>>=pure。f
fmap f x
- (读起来有点复杂,只是说
是关联的)>=
- 零是一个自然数
- 如果n是一个自然数,那么Succ(n)是一个自然数
IO a ~= RealWorld -> (RealWorld, a)
这种定义也有吸引力;不过,值得注意的是,很难说forkIO对这种定义到底做了什么
putStrLn s = PutStr (s ++ "\n") (Return ())
-- this is actually read <$> getLine; real readLn throws exceptions instead of returning bottoms
readLn = GetLine (\s -> Return (read s))
infixr 2 ||
(||) :: Bool -> (Bool -> Bool)
True || True = True
True || False = True
False || True = True
False || False = False
x || y = case (x, y) of (True, True) -> True
(True, False) -> True
(False, True) -> True
(False, False) -> False
x || y = case x of True -> (case y of True -> True
False -> True)
False -> (case y of True -> True
False -> False)
(||) x = case x of True -> let f y = case y of True -> True
False -> True
in f
False -> let g y = case y of True -> True
False -> False
in g
+-------+-----------------------+
| x | (||) x |
+-------+-----------------------+
| True | |
| | +-------+-------+ |
| | | y | f y | |
| | +-------+-------+ |
| | | True | True | |
| | +-------+-------+ |
| | | False | True | |
| | +-------+-------+ |
| | |
+-------+-----------------------+
| False | |
| | +-------+-------+ |
| | | y | g y | |
| | +-------+-------+ |
| | | True | True | |
| | +-------+-------+ |
| | | False | False | |
| | +-------+-------+ |
| | |
+-------+-----------------------+
forall a . (->) a
unit :: a -> (d -> a)
unit x = \ u -> x
bind :: (d -> a) -> (a -> (d -> b)) -> (d -> b)
bind m k = \ u -> let x = m u in k x u
instance Monad ((->) a) where
return = unit
(>>=) = bind
unit :: a -> (d -> a)
unit x = \ u -> x
bind :: (d -> a) -> (a -> (d -> b)) -> (d -> b)
bind m k = \ u -> let !x = m u in k x u
next :: (d -> a) -> (d -> b) -> (d -> b)
next m w = \ u -> let !_ = m u in w u
instance Monad ((->) a) where
.
.
.
(>>) = next
main :: IO ()
main = putStr "ha" >> putStr "ha" >> putStr "!\n"
main = let x = putStr "ha" in x >> x >> putStr "!\n"
puts :: String -> (d -> ())
putc :: Char -> (d -> ())
main' :: d -> ()
main' = puts "ha" >> puts "ha" >> puts "!\n"
main' = let x = puts "ha" in x >> x >> puts "!\n"
let x = puts "ha" in x >> x
let x = puts "ha" in \ u -> let !_ = x u in x u
testme n = n^2 + n^2 + n
testme n = let x = n^2 in x + x + n
let x = puts "ha" in \ u -> let !u1:u2:_ = ... in
let !_ = x u1 in x u2
bind :: (d -> a) -> (a -> (d -> b)) -> (d -> b)
bind m k = \ u -> let !u1:u2:_ = ... in
let !x = m u1 in
k x u2
next :: (d -> a) -> (d -> b) -> (d -> b)
next m w = \ u -> let !u1:u2:_ = ... in
let !_ = m u1 in
w u2
let x = puts "ha" in \ u -> let !u1:u2:_ = ... in
let !_ = x u1 in x u
data OI
putstr :: String -> OI -> ()
putchar :: Char -> OI -> ()
getchar :: OI -> Char
next :: (OI -> a) -> (IO -> b) -> OI -> b
next m w = \ u -> let !u1:u2:_ = ... in
let !_ = m u1 in
w u2
next :: (OI -> a) -> (IO -> b) -> OI -> b
next m w = \ u -> let !u1:u2:_ = parts u in
let !_ = m u1 in
w u2
class Partible a where
parts :: a -> [a]
partsOI :: OI -> [OI]
instance Partible OI where
parts = partsOI
putstr s = \ u -> foldr (\!_ -> id) () $ zipWith putchar s $ parts u
bind :: (OI -> a) -> (a -> OI -> b) -> OI -> b
bind m k = \ u -> let !u1:u2:_ = parts u in
let !x = m u1 in
k x u2
unit :: a -> OI -> a
unit x = \ u -> x
let x = puts "ha" in \ u -> let !u1:u2:_ = ... in
let !_ = x u1 in unit () u
let x = puts "ha" in \ u -> let !u1:u2:_ = ... in
let !_ = x u1 in x u
unit x = \ u -> let !_:_ = parts u in x
part u :: Partible a => a -> (a, a)
part u = let !u1:u2:_ = parts u in (u1, u2)
parts u = let !(u1, u2) = part u in u1 : part u
class Partible a where
part :: a -> (a, a)
parts :: a -> [a]
-- Minimal complete definition: part or parts
part u = let !u1:u2:_ = parts u in (u1, u2)
parts u = let !(u1, u2) = part u in u1 : part u
partOI :: OI -> (OI, OI)
instance Partible OI where
part = partOI
unit :: a -> OI -> a
unit x = \ u -> let !(_, _) = part u in x
bind :: (OI -> a) -> (a -> OI -> b) -> OI -> b
bind m k = \ u -> let !(u1, u2) = part u in
let !x = m u1 in
k x u2
next :: (OI -> a) -> (IO -> b) -> OI -> b
next m w = \ u -> let !(u1, u2) = part u in
let !_ = m u1 in
w u2
main' :: OI -> ()
-- the OI ADT:
data OI
putchar :: Char -> OI -> ()
getchar :: OI -> Char
partOI :: OI -> (OI, OI)
class Partible a where
part :: a -> (a, a)
parts :: a -> [a]
-- Minimal complete definition: part or parts
part u = let !u1:u2:_ = parts u in (u1, u2)
parts u = let !(u1, u2) = part u in u1 : part u
instance Partible OI where
part = partOI
putstr :: String -> OI -> ()
putstr s = \ u -> foldr (\!_ -> id) () $ zipWith putchar s $ parts u
unit :: a -> OI -> a
unit x = \ u -> let !(_, _) = part u in x
bind :: (OI -> a) -> (a -> OI -> b) -> OI -> b
bind m k = \ u -> let !(u1, u2) = part u in
let !x = m u1 in
k x u2
next :: (OI -> a) -> (IO -> b) -> OI -> b
next m w = \ u -> let !(u1, u2) = part u in
let !_ = m u1 in
w u2
instance Monad ((->) OI) where
return = unit
(>>=) = bind
(>>) = next
{- main' :: OI -> () -}
newtype IO' a = IO' (FauxWorld -> (FauxWorld, a))
data FauxWorld = FW OI
instance Monad IO' where
return x = IO' $ \ s@(FW _) -> (s, x)
IO' m >>= k = IO' $ \ s@(FW _) -> let !(s', x) = m s in
let !(IO' w) = k x in
w s'
putChar' :: Char -> IO' ()
putChar' c = IO' $ \ (FW u) -> let !(u1, u2) = part u in
let !_ = putchar c u1 in
(FW u2, ())
putStr' :: String -> IO' ()
putStr' s = IO' $ \ (FW u) -> let !(u1, u2) = part u in
let !_ = putstr s u1 in
(FW u2, ())
getChar' :: IO' Char
getChar' = IO' $ \ (FW u) -> let !(u1, u2) = part u in
let !c = getchar u1 in
(FW u2, c)