Haskell IO、木薯文档、Data.csv

cka*_*cka 1 csv io haskell decode read.csv

我正在尝试用 Haskell 学习 IO,但我发现它非常令人困惑。浏览了“use :”cassava关于 hackage 的文档decodeByName

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V

data Person = Person
    { name   :: !String
    , salary :: !Int
    }

instance FromNamedRecord Person where
    parseNamedRecord r = Person <$> r .: "name" <*> r .: "salary"

main :: IO ()
main = do
    csvData <- BL.readFile "salaries.csv"
    case decodeByName csvData of
        Left err -> putStrLn err
        Right (_, v) -> V.forM_ v $ \ p ->
            putStrLn $ name p ++ " earns " ++ show (salary p) ++ " dollars"

Run Code Online (Sandbox Code Playgroud)

我这里有两个问题

  1. 在反对名称的声明中,Person他们使用了!String而不是String,为什么?我运行了相同的示例String,输出没有差异。堆栈构建器网站上的教程也使用!. 我在这里缺少什么?

  2. 在main函数中做了什么

            Right (_, v) -> V.forM_ v $ \ p ->
                putStrLn $ name p ++ " earns " ++ show (salary p) ++ " dollars"
    
    Run Code Online (Sandbox Code Playgroud)

    做?

我知道这post $ \ p是一个匿名函数,它放置一个新的字符串,连接来自psalary来自p显示的名称salary,因为它是一个整数。

p代表什么?它是一个元组,一个变量吗?它们用于p数据Person结构吗?

这个表达是什么Right (_, v) -> V.forM_ v 意思?

小智 5

!在类型被称为 a 之前BangPattern,它会导致在构造数据类型时将参数评估为弱头范式。通俗地说,它减少了懒惰的程度,在某些情况下这会提高性能。

Right (_, v) -> V.forM_ v $ \p -> ...v在您的类型为Vector的情况 下,此部分模式与行匹配Person是包V.forM_类型的函数。本质上,它对向量的每个元素执行一个单子操作,在您的例子中,是类型为 的操作。所以在这种情况下,是一个个体。Monad m => Vector a -> (a -> m b) -> m ()vectorIOPerson -> IO ()pPerson

  • @cka 根据经验,始终使用“!”。有一个语言扩展可以自动执行此操作。在文件顶部添加“{#- LANGUAGE StrictData -#}”。查看 [Kowainik](https://kowainik.github.io/posts/2019-02-06-style-guide#strictness) 博客以获取更多参考 (2认同)
  • 我想我会稍微调整一下经验法则:使用`!`除非该字段是递归的,即包含与当前定义的类型相同的子项。延迟生成递归值并让消费者选择要查看值的哪些部分是[非常惯用的](/sf/ask/550795521/)。 (2认同)