Haskell 新手 我是怎么得到 IO ( IO String )
Haskell beginner how did I get to IO ( IO String )
所以我想学习一些 Haskell(无聊的夜班),我编写了一个程序,通过计算任何给定时间段的班次,可以简化我的假期计划.
import System.Environment
import Data.List
import Data.List.Split
import Data.Time
import Data.Time.Calendar.WeekDate (toWeekDate)
-- merge xs and ys lists alternating value from each [ xs(0),ys(0),(xs(1),ys(1)..xs(n),ys(n) ]
merge :: [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = x : y : merge xs ys
-- get part of list from index 'start' to 'stop'
slice :: Int -> Int -> [a] -> [a]
slice start_from stop_at xs = fst $ splitAt (stop_at - start_from) (snd $ splitAt start_from xs)
timeFormat = "%d-%m-%Y"
timeFormatOut :: Day -> String
timeFormatOut = formatTime defaultTimeLocale "%d-%m-%Y"
-- parses Strings to DateTime Day1
parseMyDate :: String -> Day
parseMyDate = parseTimeOrError True defaultTimeLocale timeFormat
-- 8 week shift rotation
shiftRotation = cycle ["NAT","NAT","NAT","NAT","NAT","NAT","NAT","-","-","-","-","-","-","-","DAG","DAG","DAG","DAG","-","AFT","AFT","-","-","DAG","DAG","DAG","-","-","DAG","DAG","DAG","-","DAG","DAG","DAG","DAG","DAG","-","DAG","DAG","-","-","AFT","AFT","AFT","AFT","AFT","-","-","DAG(r)","DAG(r)","DAG(r)","DAG(r)","DAG(r)","(r)","(r)"]
hs_findshift :: String -> String -> String -> IO String
hs_findshift anchor start end = do
let dayZero = parseMyDate anchor
let startDate = parseMyDate start
let endDate = parseMyDate end
let startPos = fromIntegral (diffDays startDate dayZero)
let endPos = fromIntegral (diffDays endDate dayZero) + 1
let period = slice startPos endPos shiftRotation
let dates = map (timeFormatOut) [startDate..endDate]
let listStr = (concat(intersperse "," (merge dates period)))
putStrLn listStr
这很好用。现在我会尝试将它导出到 C# 应用程序,这样我就可以制作一个漂亮的界面。我遇到了一些麻烦。我加了
module Shiftlib where
import Foreign.C.String
import Foreign.C.Types
到顶部。在导入的正下方,我添加了一个块来将输入和输出转换为 C 类型。
foreign export ccall findshift :: CString -> CString -> CString -> IO CString
findshift :: CString -> CString -> CString -> IO CString
findshift a s e = do
anchor <- peekCString a
start <- peekCString s
end <- peekCString e
result <- hs_findshift anchor start end
return $ newCString result
现在无法编译。 "return $ newCString result" return 似乎是 "foreign" 调用不接受的 IO ( IO CString )。
:l shiftlib
[1 of 1] Compiling Shiftlib ( shiftlib.hs, interpreted )
shiftlib.hs:53:1: error:
* Illegal foreign declaration: requires unregisterised, llvm (-fllvm) or native code generation (-fasm)
* When checking declaration:
foreign export ccall "findshift" findshift
:: CString -> CString -> CString -> IO CString
|
53 | foreign export ccall findshift :: CString -> CString -> CString -> IO CString
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
shiftlib.hs:61:5: error:
* Couldn't match type `IO CString' with `GHC.Ptr.Ptr CChar'
Expected type: IO CString
Actual type: IO (IO CString)
* In a stmt of a 'do' block: return $ newCString result
In the expression:
do anchor <- peekCString a
start <- peekCString s
end <- peekCString e
result <- hs_findshift anchor start end
....
In an equation for `findshift':
findshift a s e
= do anchor <- peekCString a
start <- peekCString s
end <- peekCString e
....
|
61 | return $ newCString result
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
我似乎无法绕过它。如何从我的小模块中 return CString?
newCString :: String -> IO String
result :: String
newCString result :: IO String
return :: a -> IO a
return $ newCString result :: IO (IO String)
当你已经拥有你想要的东西时就停下来,newCString result
。
当您在 IO
monad 中工作时,在 foo :: .. -> .. -> IO T
类型的函数中
do
块中的最后一个条目必须具有类型 IO T
.
return
存在,因此如果您只有 T
,您可以将其包装在 IO
中。本质上,T
类型的表达式求值为 T
类型的值,没有任何副作用(例如打印消息或改变 IORef
s)。 return
将该值转换为 IO T
类型的 IO 计算。类型 IO T
适用于 可能 在 returning T
之前有副作用的表达式。 return
创建一个没有副作用的计算,作为 IO T
.
的一个简单子案例
newCString result
已经是 IO CString
类型了,所以如果你使用 return
你会把它包装太多次,就像 IO (IO CString)
类型的东西一样。这是一个不 return 字符串的计算,而是 运行 的另一个计算(最终会产生一个字符串)。
这里显而易见的解决方案是删除 return
以避免多余的包装。
另一个不推荐的解决方案是
do ...
...
string <- newCString result
return string
这会起作用,因为 string
的类型是 String
,而不是 IO CString
。不推荐这样做,因为它是多余的。事实上,我们甚至可以添加更多的冗余
do ...
...
string <- newCString result
string2 <- return string
string3 <- return string2
return string3
效果相同。但这没有任何意义,而且会影响可读性。
你的代码是完美的。也许您还想考虑使用 "applicative style".
的一些替代方案
findshift :: CString -> CString -> CString -> IO CString
findshift a s e = do
result <- hs_findshift <$> peekCString a <*> peekCString s <*> peekCString e
newCString result
甚至
findshift :: CString -> CString -> CString -> IO CString
findshift a s e =
hs_findshift <$> peekCString a <*> peekCString s <*> peekCString e >>= newCString
(不过我不喜欢最后一个。)
所以我想学习一些 Haskell(无聊的夜班),我编写了一个程序,通过计算任何给定时间段的班次,可以简化我的假期计划.
import System.Environment
import Data.List
import Data.List.Split
import Data.Time
import Data.Time.Calendar.WeekDate (toWeekDate)
-- merge xs and ys lists alternating value from each [ xs(0),ys(0),(xs(1),ys(1)..xs(n),ys(n) ]
merge :: [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = x : y : merge xs ys
-- get part of list from index 'start' to 'stop'
slice :: Int -> Int -> [a] -> [a]
slice start_from stop_at xs = fst $ splitAt (stop_at - start_from) (snd $ splitAt start_from xs)
timeFormat = "%d-%m-%Y"
timeFormatOut :: Day -> String
timeFormatOut = formatTime defaultTimeLocale "%d-%m-%Y"
-- parses Strings to DateTime Day1
parseMyDate :: String -> Day
parseMyDate = parseTimeOrError True defaultTimeLocale timeFormat
-- 8 week shift rotation
shiftRotation = cycle ["NAT","NAT","NAT","NAT","NAT","NAT","NAT","-","-","-","-","-","-","-","DAG","DAG","DAG","DAG","-","AFT","AFT","-","-","DAG","DAG","DAG","-","-","DAG","DAG","DAG","-","DAG","DAG","DAG","DAG","DAG","-","DAG","DAG","-","-","AFT","AFT","AFT","AFT","AFT","-","-","DAG(r)","DAG(r)","DAG(r)","DAG(r)","DAG(r)","(r)","(r)"]
hs_findshift :: String -> String -> String -> IO String
hs_findshift anchor start end = do
let dayZero = parseMyDate anchor
let startDate = parseMyDate start
let endDate = parseMyDate end
let startPos = fromIntegral (diffDays startDate dayZero)
let endPos = fromIntegral (diffDays endDate dayZero) + 1
let period = slice startPos endPos shiftRotation
let dates = map (timeFormatOut) [startDate..endDate]
let listStr = (concat(intersperse "," (merge dates period)))
putStrLn listStr
这很好用。现在我会尝试将它导出到 C# 应用程序,这样我就可以制作一个漂亮的界面。我遇到了一些麻烦。我加了
module Shiftlib where
import Foreign.C.String
import Foreign.C.Types
到顶部。在导入的正下方,我添加了一个块来将输入和输出转换为 C 类型。
foreign export ccall findshift :: CString -> CString -> CString -> IO CString
findshift :: CString -> CString -> CString -> IO CString
findshift a s e = do
anchor <- peekCString a
start <- peekCString s
end <- peekCString e
result <- hs_findshift anchor start end
return $ newCString result
现在无法编译。 "return $ newCString result" return 似乎是 "foreign" 调用不接受的 IO ( IO CString )。
:l shiftlib
[1 of 1] Compiling Shiftlib ( shiftlib.hs, interpreted )
shiftlib.hs:53:1: error:
* Illegal foreign declaration: requires unregisterised, llvm (-fllvm) or native code generation (-fasm)
* When checking declaration:
foreign export ccall "findshift" findshift
:: CString -> CString -> CString -> IO CString
|
53 | foreign export ccall findshift :: CString -> CString -> CString -> IO CString
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
shiftlib.hs:61:5: error:
* Couldn't match type `IO CString' with `GHC.Ptr.Ptr CChar'
Expected type: IO CString
Actual type: IO (IO CString)
* In a stmt of a 'do' block: return $ newCString result
In the expression:
do anchor <- peekCString a
start <- peekCString s
end <- peekCString e
result <- hs_findshift anchor start end
....
In an equation for `findshift':
findshift a s e
= do anchor <- peekCString a
start <- peekCString s
end <- peekCString e
....
|
61 | return $ newCString result
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
我似乎无法绕过它。如何从我的小模块中 return CString?
newCString :: String -> IO String
result :: String
newCString result :: IO String
return :: a -> IO a
return $ newCString result :: IO (IO String)
当你已经拥有你想要的东西时就停下来,newCString result
。
当您在 IO
monad 中工作时,在 foo :: .. -> .. -> IO T
类型的函数中
do
块中的最后一个条目必须具有类型 IO T
.
return
存在,因此如果您只有 T
,您可以将其包装在 IO
中。本质上,T
类型的表达式求值为 T
类型的值,没有任何副作用(例如打印消息或改变 IORef
s)。 return
将该值转换为 IO T
类型的 IO 计算。类型 IO T
适用于 可能 在 returning T
之前有副作用的表达式。 return
创建一个没有副作用的计算,作为 IO T
.
newCString result
已经是 IO CString
类型了,所以如果你使用 return
你会把它包装太多次,就像 IO (IO CString)
类型的东西一样。这是一个不 return 字符串的计算,而是 运行 的另一个计算(最终会产生一个字符串)。
这里显而易见的解决方案是删除 return
以避免多余的包装。
另一个不推荐的解决方案是
do ...
...
string <- newCString result
return string
这会起作用,因为 string
的类型是 String
,而不是 IO CString
。不推荐这样做,因为它是多余的。事实上,我们甚至可以添加更多的冗余
do ...
...
string <- newCString result
string2 <- return string
string3 <- return string2
return string3
效果相同。但这没有任何意义,而且会影响可读性。
你的代码是完美的。也许您还想考虑使用 "applicative style".
的一些替代方案findshift :: CString -> CString -> CString -> IO CString
findshift a s e = do
result <- hs_findshift <$> peekCString a <*> peekCString s <*> peekCString e
newCString result
甚至
findshift :: CString -> CString -> CString -> IO CString
findshift a s e =
hs_findshift <$> peekCString a <*> peekCString s <*> peekCString e >>= newCString
(不过我不喜欢最后一个。)